1. 编译器默认添加的函数
自写类的时候,如果没有显式的写出来构造函数、析构函数、拷贝构造函数、拷贝赋值函数。如果程序中这些函数被需要(被调用)
,编译器就会默认的创建这些函数。
默认的构造函数和析构函数都是空实现的。
默认的拷贝构造函数和拷贝赋值函数都是浅拷贝。
如果有自己写的一个或者多个构造函数(不管有无参数),那么编译器都不会再添加默认的构造函数。
2. 如何禁止拷贝构造函数、拷贝赋值函数?
可以将拷贝构造函数、拷贝赋值函数显式的定义为private
。这样可以,但是并不是绝对的安全,因为此时,类的成员函数、友元类、友元函数,依然可以调用这些函数。
比较好的做法是,将函数声明
为private
的,同时不对该函数进行定义
。
此后,如果直接调用这两个函数,会在编译期报错。如果用友元或者成员函数调用,会在连接期报错。
也可以单独写一个unCopyable
类,然后base 私有继承unCopyable
,base内不用再声明拷贝构造和拷贝赋值,这样的操作,会将错误从连接时期提前至编译时期。
3. virtual 修饰的析构函数
一个子类对象经由一个父类指针delete时,如果父类的析构函数不是虚函数,那么执行delete后,该子类对象是“部分销毁”的,子类对象内部继承自父类的资源都会被释放掉,但是子类自己独有的资源可能会造成泄漏
。
一个原则是:如果类中没有虚函数,表明该类不想被继承,那么析构函数也不需要弄成虚函数;如果一个类中有至少一个虚函数,表明该类有可能被继承,那么析构函数最好弄成虚函数。
4. 纯虚函数与纯虚析构函数的区别
一个类,一旦内部有一个纯虚函数
,那么该类就是一个抽象类
,无法实例化。只能等待被继承。
纯虚函数与纯虚析构函数的区别在于纯虚函数不需要提供定义,而纯虚析构函数需要具体定义
。原因在于:当发生多态时,通过父类指针delete子类对象时,先执行子类的析构函数,再调用父类的析构函数,从下至上逐层析构,那么抽象类的纯虚析构函数,如果没有具体实现,在连接时
,就会报错,所以必须要有具体实现。保证继承体系的完整析构过程。