1. 委托构造函数

  • 同一个类内部,一个构造函数调用本类的另一个构造函数,减少构造函数重复代码。
  • 写在初始化列表中,调用同类其他构造函数,不能在函数体内调用
class A
{
public:
    //委托构造:无参构造委托给带参构造
    A() : A(0)
    {
    }
    A(int x)
    {
        _x = x;
    }
private:
    int _x;
};

对象创建流程:

  • 执行 A(),初始化列表调用 A(0)
  • 先执行 A(int x) 的初始化列表、函数体
  • 再回来执行 A() 的函数体

2. 示例程序

image
输出结果:
image

3. 委托构造函数注意事项

  • 只能写在初始化列表,函数体内调用无效
Person()
{
    Person("xxx",10); // 错误!这是创建临时对象,不是委托构造
}
  • 不能循环委托
A() : A(1) {}
A(int x) : A() {} // 循环委托,编译报错
  • 初始化列表中,委托构造不能和其他成员初始化混用
// 错误!委托构造时不能同时初始化其他成员
Person() : Person("test",10), _a(100){}

一旦使用委托构造,初始化列表只能有这一个委托调用,不能再写其他成员初始化。

  • 析构顺序:被委托的构造完成后,再执行委托方构造函数体;对象销毁正常调用一次析构,不会多次析构。

4. 继承构造函数

子类通过 using 父类::父类构造函数;,直接继承父类全部构造函数,不需要在子类重复转发构造参数。
场景:子类没有新增成员变量,只想复用父类构造,不用手写一堆构造转发。

class Base
{
public:
    Base() { cout << "Base()" << endl; }
    Base(int x) { cout << "Base(int)" << endl; }
    Base(string s) { cout << "Base(string)" << endl; }
};

class Derived : public Base
{
public:
    //继承父类所有构造函数
    using Base::Base;
};

使用:

Derived d1;        //调用 Base()
Derived d2(10);    //调用 Base(int)
Derived d3("hi");  //调用 Base(string)

5. 继承构造函数注意事项

  • 继承过来的父类构造,只会初始化父类成员;子类自己新增成员,执行默认初始化
class Derived : public Base
{
public:
    using Base::Base;
private:
    int _son_val; //继承构造不会初始化 _son_val!随机值
};
  • 如果子类自己写了同名构造函数,子类构造优先,覆盖继承来的构造。
class Derived : public Base
{
public:
    using Base::Base;
    Derived(int x) //子类自己实现int构造,覆盖继承来的Base(int)
    {
    }
};
  • 继承构造函数不会继承:拷贝构造、析构;
  • 访问权限跟随父类:父类 private 构造不能继承;protected 继承过来在子类也是 protected。

6.对比

特性 委托构造函数 继承构造函数
作用 同一个类内部,一个构造调用本类另一个构造 子类复用父类的全部构造函数
关键字 初始化列表直接调用同类构造 using Base::Base;
调用位置 只能写在初始化列表 子类 public 块内声明
代码复用范围 本类多个构造函数 子类复用父类构造
限制 不能循环委托;不能同时初始化其他成员 子类新增成员不会初始化;子类同名构造会覆盖继承构造
运行开销 编译期语法糖,无开销 编译期语法糖,无开销