1. 类的定义:
1. 类定义格式:
对于我们的类的话,我们是把类看成一个整体,我们的函数里面没有找到我们的成员变量,我们就在我们的类里面找。
我们看我们的第二点:
我们的类里面,我们通常会对我们的成员变量加上特殊的标识符,就比如我们的图里面的成员变量我们就在前面加上_。(但是这个并不是强制的)。
我们来看我们的第三点:
我们的第三点说的是我们的struct,我们的C++兼容我们的C语言的,所以我们的C语言的代码在C++里面也可以编译通过;
然后在我们的C++里面,我们使用class来定义类,但是我们的struct进入到了我们的C++里面,他也被升级成了类,这时候,我们的C语言的struct结构体和我们的C++struct定义的类就可以同时存在了。
我们看我们上面的图片,我们的第一个是struct结构体,我们对他进行typedef的函数里面,我们的next指针还是struct ListNodeC*next;但是到了我们的C++的时候,我们的struct已经被升级成类了,我们的struct定义的类的名字就可以代表我们的类,我们可以直接使用我们的类的名字来代表类,不需要typedef。
我们看下面的:
这个是我们之前做过的题目:我们的C++,我们在上面没有typedef,我们的下面的函数就直接使用ListNode了,因为这个是C++,这个struct已经被升级成了类,我们的类的名字可以直接代表我们的类。
我们再来看我们的第四点:
我们的第四点说,我们定义在类里面的函数会被自动的定义为内联inline函数,就比如我们图中的struct类里面定义的Init函数,但是他到底能不能成为真正的内联函数,还是要看编译器;
2. 访问限定符:
我们还是先看第一点:
我们的第一点说:C++⼀种实现封装的⽅式,⽤类将对象的属性与⽅法结合在⼀块,让对象更加完善,通过访问权限 选择性的将其接⼝提供给外部的⽤⼾使⽤。
我们再看第二点:
我们的第二点说:我们的访问限定符有三个:1. public。2. private。3. protected。
三个含义分别是:公共,私有,保护。
public修饰的成员在类外可以直接被访问;
protected和private修饰的成员在类外不能直接被访问,protected和private是⼀样的,以后继承章节才能体现出他们的区别。
我们再来看我们的第三点:
访问权限作⽤域从该访问限定符出现的位置开始直到下⼀个访问限定符出现时为⽌,如果后⾯没有 访问限定符,作⽤域就到}即类结束。
我们看着两张大的图片:在我们的类里面,我们的开始使用public来修饰,然后一直走,知道我们的下一个访问限定符出现为止。我们看我们的图片,这个也就是说明,我们的public到我们的private之间,都是公有的,就是我们在类外面可以直接进行调用的。
然后我们继续看:
我们的这个private,后面没有访问限定符了,所以就一直到花括号类的结束。
也就是说:我们的public到private里面定义的是公有的,private到结束的类域的成员变量是私有的。
这时候你来看,我们从类的外部来访问我们的公有的Top函数,这就可以,但是我们访问我们的私有的top变量的时候,这就错了。
我们来看我们的第四点:
class定义成员没有被访问限定符修饰时默认为private,struct默认为public。
我们来看我们的这个class类,我们一开始没有设置访问限定符,这时候我们的开始到我们的第一个访问限定符public之间的话,都是私有的,因为我们的class类没有访问限定符的修饰的时候,他就是私有的。所以我们看我们的上面的代码:我们的Init就是私有的函数,然后我们的public到再下一个访问限定符这部分就是公有的。
class类是这样的,但是struct类的话,我们不写访问限定符的话,它默认就是公有的。
3. 类域:
我们的类域和namespace域是不会影响我们的生命周期;
我们先看我们的上面的图片:当我们的函数含有缺省值的时候,我们的缺省值只能在函数声明的时候给,不能在定义的时候给,
我们继续来看:当我们定义我们的函数的时候,我们使用我们的函数就必须加上Stack::,因为这个是我们类里面的成员函数,如果我们不加域作用限定符的时候,我们的编译器就会认为这是一个全局函数,我们的编译器就会去局部域,全局域里面去寻找,但是我们的编译器是不会主动的去namespace,或者类里面去寻找,这时候他在局部和全局域里面没找到,他就会报错。
我们这里有一个点:其实我们在上面已经说了,我们的类里面定义的函数,是内联函数,一些比较长的函数,我们就在类里面声明,比较短的函数,我们就在类里面直接定义,这些直接被定义的函数就是内联函数。
2. 实例化:
1. 类的实例化的概念:
我们的类和对象,之间是什么关系呢?
我们的类实例化出了对象;
我们的类就像是造房子的图纸,我们的对象就是建造的房子;
2. 对象大小:
那我们的对象的大小是多少呢?
这个就是我们的一个类,我们使用它实例化出一个对象,我们求一下这个对象的大小。
首先我们看我们的三个成员变量,三个数据合起来是12个字节(内存对其规则)
然后还有我们的成员函数,我们先来看一下最终的结果是多少?
我们这里就发现,我们这个对象最终的大小就是12,这是啥意思,我们就没有算成员函数的大小,我们只计算成员变量的大小。
那我们来看一下这个是咋回事:
我们看一下我们的对象的存储方式:我们这里有两种存储的方式:
第一种:我们把对象的成员变量和成员函数都存起来,(我们存储成员函数的话,一定存储的是成员函数的指针,因为我们的成员函数的代码很多,我们不可能把他全存进去。)
我们的另外的一种方法是不存;
因为我们的每个对象的成员变量是不一样的,但是每个对象的成员函数调用的都是一样的。
我们的对象是不会存储我们的成员函数的,我们只会存储成员变量,然后我们的成员函数存储到公共的代码区域。
我们在这里找几个题目练习一下:
我们看我们的这个对象的大小:我们不管成员函数的大小,我们就看一下成员变量的大小,判断一下内存对齐,最终的结果就是8个字节;
我们再来判断一下这个B和C对象的大小:
这时候里面的成员变量一个都没有,成员函数的话,这就不算,所以这时候他的大小是多少呢?
我们可以看见,虽然它里面的话,什么东西都没有,但是他的大小为1,这里的这个1纯粹就是为了占位置用的。
我们的这个1就是为了表示这个对象存在过。
3. this指针:
我们先来看一下我们的这个:
我们看我们的这两个对象调用的是同一个函数,然后我们看我们的函数,但是为什么他打印出来的数据是一样的呢?
其实,在我们的成员函数里面,我们的函数其实都会加上一个参数,this指针。
我们看我们的成员函数,我们的Init函数看着有三个参数,其实有4个参数,我们的形参的开头实际上有一个this指针,我们的Print函数,看起来没有参数,实际上是有一个参数的。
我们的函数,其实是会把d1,和d2的地址传过去的,然后this指针来接收,然后this指针进行解引用得到我们的对象d1里面的year,month,day。
但是我们的这里,编译器是不允许你显示的把地址传过去,也不能显示的展出this指针,这是不允许的。
补充:
我们补充一下知识点:
我们看我们的下面的图片:
我们的第一个const修饰的是我们的p1指针指向的数据,这个数据是不能改变的。
然后我们的第二个,这个const修饰的我们的指针本身,也就是说我们的指针的指向不能改变。
我们的指针的指向不能改变,那我们的这个指针一开始就必须要进行初始化。