一、默认构造函数

1、=default  和 =delete

= default   // 只能用于不带参数的构造函数,不能用于带参,或者普通函数
= delete    // 禁止系统给我们生成默认的不带参数的构造函数

2、explicit

一般只带一个默认参数的构造函数前面会加explicit,避免一些数字会隐式的转化成我们的类型

 

二、复制构造函数

1、系统默认的复制构造函数,是从源对象到目标对象逐字节拷贝。

2、复制构造函数被调用的三种情况

// 1、用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用
Element  p2(p1);   // Element 是自定义类型,
Element  p2  = p1;  
// 如果是下面的情况,是赋值而不是初始化,不会调用复制构造函数
Element  p1 , p1;  
p2  = p1;           //  该句为赋值语句,不是初始化语句
// 2、作为函数的形参,参数传值时,调用了复制构造函数
void Func1(Element ele);   //  调用函数的申明
Element p1;
Func1(p1);              // 对象作为函数参数传值时,会调用复制构造函数
void Func2(Element& ele);   //  调用函数的申明,此时传入的参数是引用类型
Func2(p1);             // 如果传入的参数是引用类型,则不会有拷贝构造函数的调用
// 3、自定义类型作为函数的返回值
Element Func()    // 该函数返回局部变量a时,调用了复制构造函数,返回一个临时的Element变量
{
    Element a;
    return a;
}
Func() ;      // 当调用这个函数时,如果没有接住这个返回值,则复制构造函数形成的临时变量在执行完这句话后,就析构了。

 3、无参构造函数不一定存在,但是复制构造函数总会存在

 

三、虚析构函数

class Base
{
public:
    Base() {
        cout << "Base构造" << endl;
    }
    virtual ~Base() {  // 注意:如果此处不是virtual,则delete Base指针时,不会调用子类析构函数
        cout << "Base析构" << endl;
    }
};

class Element : public Base
{
public:
    Element() {
        cout << "Element构造" << endl;
    }
    ~Element() {
        cout << "Element析构" << endl;
    }
};

int main()
{
    Base* p = new Element;
    delete p;   // 注意:如果Base类的析构函数不是虚函数,则该处只会执行Base的析构函数
    // 所以,基类的析构函数一定要是虚函数  
    system("pause");
    return 0;
}

小结:基类中如果有虚函数,则基类的析构函数一定要是虚函数,因为这样,当基类指针指向派生类时,在delete 基类指针时才会调用派生类的析构函数