【C++笔记】C++之类与对象(上)

【C++笔记】C++之类与对象(上)

1、类是结构体的升级

C++的一个显著特征就是兼容C语言,所以C++把结构体"升级"成了"类",之所以是"升级"是因为,在C++中的结构体及支持以前C语言的结构体的玩法,也可以支持C++中类的玩法。

例如单链表节点这个类,我们既可以写成纯C版本:

用纯C的写法,我们每次要定义一个节点变量的时候,都必须要加上一个前缀struct,非常的麻烦。

而且就算是我们用了typedef,在结构体内部也还是不能直接用typedef后的符号,因为在结构体内部typedef还没有起作用:

非常麻烦!

但在C++中,我们就不必要担心这些情况,因为在C++中,结构体也被当成了类,而类是直接可以类名来定义变量的:

不管类内部还是外部,我们都可以直接使用类名来定义变量。

2、类中可以定义的东西

既然类是结构体的"升级",那么内在结构体中定义的东西也一定能在类中定义,所以类中能定义的包括:

各种变量:

数组:

还有枚举和结构体等等:

几乎可以定义所有的东西:

但C++的类除了可以定义以上这些东西之外,还一个定义一个类独有的东西:"成员函数",

有了成员函数,我们在管理结构体中的各个成员的时候就可以更方便,而不需要每写一个函数就需要传参。

例如栈这个类的初始化:

这是因为类划分了一个"类域",在成员函数被调用的时候,就回到类中去寻找各个变量,这就不需要我们老是传递参数了。

而且使用起来也很简单,就像以前结构体访问成员变量一样:

而这个"public"是一个类访问限定符。

3、类访问限定符

在一个类中,我们总有些东西是不想被外面访问到的,也总有一些东西是想要对外开放的,这时候就需要访问限定符来管理了。

访问限定符一共有三个:

cpp 复制代码
public(公有)
protected(保护)
private(私有)

第一个public表示公开,由这个访问限定符修饰的成员不管是在类内部还是外部,都可以自由访问:

而第二个protected,我们现在暂且认为它和public是一样的,因为这个访问限定符实在以后的类的继承中才能显现出区别的。

第三个private表示私有,被这个访问限定符所修饰的成员就只能在类里边访问,而在类外边是访问不到的:

而要是我们不显示的添加访问限定符,在类和结构体中也是有默认的访问限定符的。

其中,类的默认访问限定符是private:

而结构体的默认访问限定符是public:

4、类的声明

大家是否有过一个疑问?就是我们平时写的这样一个类:

它到底是声明还是定义呢?

首先我们要明确声明和定义的区别,声明只是告诉编译器,有这么一个函数或变量存在,而定义则是为这个函数或变量开辟空间。

所以我们就可以想接下来这样来验证上面所写的到底是声明还是定义:

我们发现用域作用限定符是访问不到成员的,这就说明编译器并没有为这个类开辟空间。所以编译器找不到这个成员的地址。

5、类的实例化(定义)

有声明就得有定义,其实我们平时创建的一个类对象就是一个类的定义,也称为类的实例化:

这样,编译器才会真正开辟空间。

6、类的大小的计算

其实类的大小计算遵循着结构体内存对齐的规则,例如下面这两个类和结构体:

从结果就可以看出类大小的计算也是遵循着结构体内存对齐的那套规则的。

同时不管我们是使用类名来计算的小还是使用类对象来计算大小,都是可以准确算出一个类的大小的:

这是因为就算我们没有实例化类对象,但通过类名我们还是可以找到类的声明,类的生命虽然没有开辟空间,但也相当有了一张"图纸",我们可以通过这张"图纸"来计算出类的大小。

但是有一点是不一样的,就是当类中存在成员函数的时候:

我们发现,就算类中添加了成员函数,类的大小还是没有发生改变,这是为什么呢?

其实这是一种节约资源的做法,我们不妨先想一想,我们平时定义的各个类对象,他们的成员变量是否是相同的变量?

答案显然不是的。

但它们所调用的函数是不是同一个呢?

答案是是的,因为函数的逻辑都是一样的,而各个对象的成员变量的值是可能各不相同的,不相同的只当然不能共用同一个变量了,但是相同的逻辑就只需要一段相同的指令就行了。

所以,类中就没有必要存储成员函数了。类中的成员函数其实是放在代码段中的。

但要是,我有一个"空类",也就是类中没有成员变量也没有成员函数,那这个类的大小又该是多少呢?

我们可以来验证一下:

我们可以看到,空类的大小是1字节。

其实这一字节的作用只是用来占位而已,只是表示这个类存在过。

7、this指针

经过前面的叙述,我们已经知道成员函数并不存储在类中。那么问题来了,既然不存储在类中,那么在调用的时候就必定需要传参啊,那为什么在写成员函数的时候不需要传递成员变量呢?

其实,所谓的"不用传参"只是表面现象而已,其实只是把传递对象的工作交给了编译器来做而已。

事实上,我们平时写的成员函数还有一个隐藏的参数:"this"指针,这个指针是一个类对象的指针,也就是调用函数的对象的指针:

例如下面这个函数,编译器会在底层将它处理成这样的一个函数:

但这是规定给编译器做的工作,也就是说我们不能和编译器"抢工作",不能显示的将this指针,写在参数列表中。

但我们却可以在类当中使用它,例如上面的这个函数也可以这样写:

但是像这种单纯访问成员变量的情况,我们一般都不会显示的将this写出来,因为编译器自己会自动补上,何必自己给自己找麻烦呢?

相关推荐
暗黑起源喵1 分钟前
设计模式-工厂设计模式
java·开发语言·设计模式
鸭鸭梨吖4 分钟前
产品经理笔记
笔记·产品经理
WaaTong6 分钟前
Java反射
java·开发语言·反射
Troc_wangpeng7 分钟前
R language 关于二维平面直角坐标系的制作
开发语言·机器学习
努力的家伙是不讨厌的9 分钟前
解析json导出csv或者直接入库
开发语言·python·json
Envyᥫᩣ22 分钟前
C#语言:从入门到精通
开发语言·c#
齐 飞30 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
童先生43 分钟前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
lulu_gh_yu44 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!1 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法