拷贝构造函数调用时机
所谓调用时机指的是代码中出现下边三种情形时,会调用对象的拷贝构造函数
1.使用一个已经创建完毕的对象初始化一个新对象
2.以值传递的方式给函数参数传值
3.以值方式返回局部对象
深拷贝与浅拷贝
编译器默认的拷贝构造函数属于浅拷贝,所谓浅拷贝指的是在拷贝构造函数中完全逐字节对类的成员变量进行拷贝,包括在堆区存储的成员变量,也完全拷贝其地址。这就造成堆区成员变量重复释放的问题。因此,需要深拷贝,即重新开辟一段新的内存作为拷贝出来的对象的堆区变量。
初始化属性
静态成员变量
1.所有对象共享同一份内存;
2.编译阶段分配空间;
3.类内声明。类外初始化
对象特性 静态成员函数
1.静态成员函数有两种访问方式:(1)对象访问;(2)类名访问
2.静态成员函数可以访问静态成员变量,不可以访问非静态成员变量,原因是通过类名访问时无法区分到底是哪个对象的成员变量
3.静态成员函数:所有对象共享同一个函数,静态成员函数只能访问静态成员变量。
空指针访问成员函数
Person * p = NULL;
p->hanshu1;
若hanshu1中不出现this指针,则p可以正常调用成员函数hanshu1,若存在,则报错。
const修饰成员函数
成员函数后加const后我们称这个函数为常函数
常函数内不可以修改成员属性
解释:this指针是一个指针常量(指针常量指向一个对象,便不能再指向其他地方,但可以修改指向的值),成员函数后加了const(修饰的是this指针)之后相当于在指针常量this(Person* const this)前再加一个const(const Person* const this)即this常量指针常量,既不可以修改指向,也不可以修改指向的值。
成员属性声明时加关键字mutable后,在常函数中依然可以修改
声明对象前加const称该对象为常对象
常对象只能调用常函数(常对象不可以调用普通成员属性,mutable修饰的成员属性常对象也可以调用)(不可以调用普通成员函数,因为普通成员函数可以修改普通成员属性但常对象不能修改普通成员属性,因此,常对象不能调用普通成员函数)
友元函数(***)
全局函数做友元函数
将全局函数void goodGay(Building* building)加一个friend添加在类的声明最前端,此时,全局函数goodGay可以访问类Building中的私有属性
friend void goodGay(Building* building);
类做友元
将goodGay类()加friend添加在类Building最前端,告诉编译器goodGay类是Building类的好朋友,可以访问Building类的私有属性,注意,goodGay中要维护一个Building(Building* building )型的指针,并且在构造函数中在堆区开辟一个Building类型。
friend class goodGay
成员函数做友元
告诉编译器 goodGay类下的visit函数可以访问building的私有属性。
friend void goodGay::visit();
运算符重载(*****)
概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
对于内置数据类型,编译器知道如何进行运算
int a = 10;
int b = 10;
int c = a + b;
继承
总结一下三个关键字的访问范围:
public: 能被类成员函数、子类函数、友元访问,也能被类的对象访问。
private: 只能被类成员函数及友元访问,不能被其他任何访问,本身的类对象也不行。
protected: 只能被类成员函数、子类函数及友元访问,不能被其他任何访问,本身的类对象也不行。
protected继承和private继承能降低访问权限:
使用private继承,父类的protected和public属性在子类中变为private
使用protected继承,父类的protected和public属性在子类中变为protected
使用public继承,父类中的protected和public属性不发生改变
利用虚继承解决菱形继承的问题
继承之前 加上关键字 virtual变为虚继承
Animal类称为虚基类
多态
静态多态:函数重载、运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现运行时多态
区别:静态多态的函数地址早绑定-编译阶段确定函数地址
动态多态的函数地址晚绑定-运行阶段确定函数地址
多态满足条件
有继承关系
子类重写父类中的虚函数
多态使用条件
父类指针或引用指向子类对象
重写:函数返回值类型 函数名 参数列表完全一致成为重写
虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方法:将父类中的析构函数改为虚析构或纯虚析构
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
虚析构和纯虚析构区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
拥有纯虚析构函数的类也属于抽象类