【C++】类与对象理解和学习(上)

news2025/1/17 18:06:37

专栏放在【C++知识总结】,会持续更新,期待支持🌹


类是什么?

类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它(实例化后才会开辟物理空间,后面会讲到);比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。也可以理解为这是一个自定义类型,与C语言中的结构体(struct)颇有类似。

struct与class

C语言中,我们知道struct是用来定义结构体的关键字,其实在C++中的struct也依然保留了在C语言中的功能,不仅如此,C++中的struct还可以用来定义函数,并且C语言中,我们用struct来定义一个结构体,那么定义一个与它同类型的变量要写成struct xxx的形式,而C++中用struct来定义一个结构体,那么同类型的变量则可以省略struct

类的定义

C++中,对于这种自定义类型的定义,其实更喜欢用class来代替struct,class为定义类的关键字,class后面为类的名字,{}内为类的主体,主体中的内容就是类的内容,分为成员变量(类的属性)以及成员函数(类的方法)。

类的两种定义的方式:

一种是将成员函数定义在类里面(编译器可能会当成内联函数处理)

另一种是将成员函数声明与定义分离(工作中推荐第二种)

这里需要注意的是,在类中定义成员函数以及成员变量时,不需要考虑定义的先后顺序,也就是说,即使成员变量放在成员函数的下面,成员函数中依然可以使用成员变量。

类访问限定符

class中有三种访问限定符:public、protected、private。

访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止,如果后面没有访问限定符,作用域就到 } 即类结束。

另外注意:class的默认访问权限为private,struct为public(因为struct要兼容C),访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

类的实例化以及调用

所谓类的实例化其实就是用类创建一个具体的实体变量,我们上面的class Person中的Person仅仅只是声明,不占用物理空间,只有实例化后,才会占有空间。当然,一个类可以进行多个实例化。

Person p;//p占有实际的物理空间,这里就是一个实例化的过程
//一个类可以进行多个实例化
Person p1;
Person p2;

我们可以通过.操作符来实现类中方法的调用(public影响的区域可以在类外直接调用

class Person
{
public://公有,在类外可以直接访问
    void Print()
    {
        //...
    }
private://私有,在类外不能直接访问
    char* _name;
    int _age;
    short _height;
};

int main()
{
    Person p;//实例化
    p.Print();//通过.来调用函数Print
    return 0;
}

类对象大小的计算

既然实例化后才会占有具体的空间,那么实例化后,它的空间大小应该是多少呢?成员函数与成员变量又是何存储的呢?假如是个空类,实例化后还会不会占用空间呢?

类对象的存储方式

实际上,成员函数虽然是定义在类中,但是它并不存储在类里,假如它是存储在类中,而每个实例化后的对象都各自拥有各自的成员函数,则会造成严重的资源浪费,因为成员函数就好比小区中的健身器材、公共厕所等公共共有的设施,只需要存在一份就足够了。成员函数实际上是存在于公共代码段中。

所以实例化后的对象的大小,只需要计算成员变量大小即可,当然,类对象大小的计算与struct一样遵循结构体内存对齐规则。这里需要注意的是,假如一个类中只有成员函数而没有成员变量,或者什么都没有,则实例化后对象的大小为1byte。

class Person
{
public://成员函数不参与大小的计算
    void Print()
    {
        //...
    }
private://遵循结构体内存对齐规则
    char* _name;
    int _age;
    short _height;
};
//空类
class test1
{};
//只有成员函数
class test2
{
public:
    void test()
    {}
};
int main()
{
    Person p;//实例化
    test1 p1;
    test2 p2;
    p.Print();//通过.来调用函数Print
    cout << sizeof(p) << endl;//12
    cout << sizeof(p1) << endl;//1
    cout << sizeof(p2) << endl;//1
    return 0;
}

结构体内存对齐规则(与C语言中的struct相同)

1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的对齐数为8
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

this指针

在上面我们知道,成员函数是属于公有的,是类实例化后的各个对象所共同使用,那么不禁有一个问题,就是既然是公有的,那么它是怎么区分是谁调用的呢?就比如说下面的一个例子:

class Date
{
public:
    //成员函数(公有的,存储在代码段中)
    void Init(int year,int month,int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()
    {
        cout << _year << "-" << _month << "-" << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1;//实例化
    Date d2;
    //函数Init是如何区分是d1还是d2调用的呢?
    d1.Init(2023, 2, 10);
    d2.Init(2022, 2, 10);
}

对于这个问题,C++是通过this指针来解决的,C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成

也就是说,虽然我们这里只是传了三个参数,但实际上还有一个隐藏的参数this指针,也就是说,编译器实际上是这么来处理的:

this指针的特性

this指针的类型为 Date* const,也就是说,this是不可被修改的,this实际上就是实例化对象的地址
this只能在成员函数内部使用
this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以 对象中不存储this指针。
this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

关于this指针为空

只要不涉及到解引用操作,程序都会正常运行,空指针也是可以调用类中的函数的,仅仅只凭借.或者->是不能判断是否涉及空指针的解引用,而是应该根据调用的函数的内容,来判断是否对空指针进行解引用。

class Test
{
public:
    void Print1()
    {
        cout <<"Print()" << endl;
    }
    void Print2()
    {
        cout << _a << endl;
    }
    void Init(int a=20)//缺省参数
    {
        _a = a;
    }
private:
    int _a;
};
int main()
{
    Test* d1 = nullptr;
    //不能仅凭借*以及->来断定就是空指针解引用

    //d1->Print1();//程序正常运行
    //d1->Print2();//程序崩溃,因为函数内容中涉及到了空指针解引用:this->_a(nullptr->_a)
    //d1->Init();//崩溃,原因同上,nullptr->_a=a;

    //(*d1).Print1();//正常运行,函数中仅仅只是打印一个字符串
    //(*d1).Print2();//崩溃,原因同上2
    //(*d1).Init();//崩溃,同上
}

封装的概念与作用

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。

就好比我们的使用计算机的时候,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此 计算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可

在C++中便可以通过类来实现数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。这样用户使用起来也会更加方便。


end

生活原本沉闷,但跑起来就会有风!🌹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/335298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视觉感知(二):车位线检测

1. 简介 本期为大家带来车位线检测相关知识点,以及算法工程落地的全流程演示。车位线检测是自动泊车领域必不可缺的一环,顾名思义就是采用环视鱼眼相机对路面上的车位线进行检测,从而识别出车位进行泊车。 较为常规的做法是使用四颗鱼眼相机环视拼接然后在鸟瞰图上做停车位…

如何利用状态机编程实现启保停控制(含Stateflow模型介绍)

状态机的介绍这里不再赘述,概念也很简单没有过多的复杂理论。下面我们直接给出具体实现过程。有限自动状态机详细讲解请参看下面的文章链接: PLC面向对象编程系列之有限状态机(FSM)详解_RXXW_Dor的博客-CSDN博客_有限状态机 plc实现编写PLC控制机器动作类程序时,当分支比较…

【自然语言处理】主题建模:BERTopic(实战篇)

主题建模&#xff1a;BERTopic&#xff08;实战篇&#xff09;BERTopic 是基于深度学习的一种主题建模方法。201820182018 年底&#xff0c;Devlinetal.Devlin\ et\ al.Devlin et al. 提出了 Bidirectional Encoder Representations from Transformers (BERT)[1]^{[1]}[1]。BER…

web自动化测试入门篇05——元素定位的配置管理

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

Window 安装 Docker

1.开启Hyper-v 2.确定后重启 3.双击安装包进行安装 4.安装完后系统重启 5.打开Docker软件提示&#xff1a;按下图操作后重启Docker 6.设置docker镜像仓库 { “experimental”: false, “features”: { “buildkit”: true }, “registry-mirrors”: [ “https://docker.mirr…

界面组件Telerik UI for WPF R1 2023——让导航栏变得更智能!

Telerik UI for WPF拥有超过100个控件来创建美观、高性能的桌面应用程序&#xff0c;同时还能快速构建企业级办公WPF应用程序。UI for WPF支持MVVM、触摸等&#xff0c;创建的应用程序可靠且结构良好&#xff0c;非常容易维护&#xff0c;其直观的API将无缝地集成Visual Studio…

大数据Kylin(一):基础概念和Kylin简介

文章目录 基础概念和Kylin简介 一、​​​​​​​OLTP与OLAP 1、​​​​​​​​​​​​​​OLTP 2、​​​​​​​​​​​​​​OLAP 3、​​​​​​​​​​​​​​OLTP与OLAP的关系 二、​​​​​​​​​​​​​​数据分析模型 1、星型模型 2、雪花模型 …

推进行业生态发展完善,中国信通院第八批RPA评测工作正式启动

随着人工智能、云计算、大数据等新兴数字技术的高速发展&#xff0c;数字劳动力应用实践步伐加快&#xff0c;以数字生产力、数字创造力为基础的数字经济占比逐年上升。近年来&#xff0c;机器人流程自动化&#xff08;Robotic Process Automation&#xff0c;RPA&#xff09;成…

【GPLT 二阶题目集】L2-012 关于堆的判断

将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种&#xff1a; x is the root&#xff1a;x是根结点&#xff1b; x and y are siblings&#xff1a;x和y是兄弟结点&#xff1b; x is the parent of y&#xff1a;x是y的父结…

MySQL数据库05——数据的查询(SELECT)

SQL强大的在于它的查询&#xff0c;查询是最重要的操作之一。 查询最基础的语法 查看student表里面全部内容&#xff1a; SELECT * FROM student整体语法格式 主要子句的语法格式归纳如下&#xff1a; SELECT [DISTINCT | ALL] select_list FROM table_sour…

MyBatis案例 | 使用映射配置文件实现CRUD操作——添加数据

本专栏主要是记录学习完JavaSE后学习JavaWeb部分的一些知识点总结以及遇到的一些问题等&#xff0c;如果刚开始学习Java的小伙伴可以点击下方连接查看专栏 本专栏地址&#xff1a;&#x1f525;JavaWeb Java入门篇&#xff1a; &#x1f525;Java基础学习篇 Java进阶学习篇&…

【GPLT 二阶题目集】L2-044 大众情人

人与人之间总有一点距离感。我们假定两个人之间的亲密程度跟他们之间的距离感成反比&#xff0c;并且距离感是单向的。例如小蓝对小红患了单相思&#xff0c;从小蓝的眼中看去&#xff0c;他和小红之间的距离为 1&#xff0c;只差一层窗户纸&#xff1b;但在小红的眼里&#xf…

肿瘤生信科研:绘制突变景观图(mutation landscape)

肿瘤生信科研经常会画突变的景观图&#xff0c;或者叫瀑布图&#xff0c;用 maftools 包可以实现简单的 Landscape 图&#xff0c;但是当图形比较复杂时&#xff0c;maftools 就不能胜任了&#xff0c;可以用 ComplexHeatmap 包来画。实际上&#xff0c;Landscape 图是热图的一…

ubuntu clion从0开始搭建一个风格转换ONNX推理网络 opencv cuda::dnn::net

系统搭建 系统搭建 OpenCV的安装 cmake sudo apt-get install cmake其他环境以来 sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg.dev libtiff5.dev libswscale-dev libjasper-dev 不安装会报这个错误 OpenCV(4.6.0) /hom…

LeetCode刷题系列 -- 48. 旋转图像

给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。示例 1&#xff1a;输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]]输出&#…

【MySQL Shell】8.8 InnoDB ClusterSet 的紧急故障切换

紧急故障切换会将选定的副本集群放入 InnoDB ClusterSet 部署的主 InnoDB 集群中。当当前主集群不工作或无法联系时&#xff0c;可以使用此过程。在紧急故障切换过程中&#xff0c;无法确保数据一致性&#xff0c;因此为了安全起见&#xff0c;在故障切换过程中将原始主集群标记…

openHarmony的UI开发

自适应布局 拉伸能力 ​ Blank在容器主轴方向上&#xff0c;空白填充组件具有自动填充容器空余部分的能力。仅当父组件为Row/Column时生效&#xff0c;即是线性布局。这样便可以在两个固定宽度或高度的组件中间添加一个Blank()&#xff0c;将剩余空间占满&#xff0c;从而实现…

通过python 调用OpenAI api_key提交问题解答

通过python 调用OpenAI api_key提交问题解答✨可以通过网页版的jupyter notebook调用&#xff0c;也可以通过spyder窗口等IDE窗口. &#x1f33c;通过python 调用OpenAI api_key接口&#xff0c;可以避免国内网页不能访问的问题。前提是需要自己已经注册了OpenAI帐号&#xff…

linux中crontab定时任务导致磁盘满和云监控未报警的的坑

一个后台开发者&#xff0c;兼职运维工作中&#xff0c;配置linux中crontab定时任务&#xff0c;导致磁盘满和云监控未报警的问题的坑。 1.磁盘满 使用命令 df -h2.问题排查 2.1排查日志 命令 cat /var/log/messages日志文件的默认路径是&#xff1a;/var/log 下面是几个…

外贸常用工具(建议顶置收藏)

领英精灵 推荐理由&#xff1a;可批量群发消息并单独显示&#xff0c;相当于20人的发送效率。 做外贸的人一定会在Linkedin平台开发客户&#xff0c;但Linkedin平台没有提供群发消息的功能&#xff0c;如果要快速发消息的话&#xff0c;只能一个一个发&#xff0c;这种发送效…