派生类构造函数(第 13 章)

← 返回虚函数 | ← 主页


目录


🔴调用基类构造函数

🔺派生类构造函数必须通过成员初始化列表调用基类构造函数,否则自动调用基类默认构造函数

class Base {
    int x;
public:
    Base(int x) : x(x) {}
};
 
class Derived : public Base {
    int y;
public:
    // ⭐ 在初始化列表中调用基类构造函数
    Derived(int x, int y) : Base(x), y(y) {}
};

🔺派生类不能直接初始化基类的 private 成员,只能通过基类构造函数传递:

// ❌ 错误:不能直接访问基类 private 成员
Derived(int x, int y) : x(x), y(y) {}
 
// ✅ 正确:通过基类构造函数
Derived(int x, int y) : Base(x), y(y) {}

🔺若基类有默认构造函数,派生类可以不显式调用:

class Base {
public:
    Base() {}  // 默认构造函数
};
 
class Derived : public Base {
    int y;
public:
    Derived(int y) : y(y) {}  // Base() 自动被调用
};

🔴构造与析构顺序

🔺构造顺序:基类构造函数 → 成员对象构造函数 → 派生类构造函数体

🔺析构顺序:与构造相反 → 派生类析构函数 → 成员对象析构函数 → 基类析构函数

class Base {
public:
    Base()  { cout << "Base 构造\n"; }
    ~Base() { cout << "Base 析构\n"; }
};
 
class Derived : public Base {
public:
    Derived()  { cout << "Derived 构造\n"; }
    ~Derived() { cout << "Derived 析构\n"; }
};
 
// 输出:
// Base 构造
// Derived 构造
// Derived 析构
// Base 析构

🔴复制构造函数与赋值运算符

🔺若派生类需要自定义复制构造函数,必须显式调用基类版本,否则基类部分只会默认初始化:

Derived::Derived(const Derived& d) : Base(d), y(d.y) {}
//                                   ^^^^^^ 调用基类复制构造函数

🔺自定义赋值运算符同理,必须显式调用基类的 operator=

Derived& Derived::operator=(const Derived& d) {
    if (this == &d) return *this;
    Base::operator=(d);  // ⭐ 调用基类赋值运算符处理基类部分
    y = d.y;
    return *this;
}

诞生时用 = 是“初始化”(复印作业);诞生后用 = 才是“赋值”(擦掉重写)。

🔺若不显式调用:基类部分会调用基类默认构造函数初始化(复制构造)或完全不更新(赋值),导致基类数据丢失


本节小结

要点说明
初始化列表调用基类Derived(args) : Base(args), 自身成员(args) {}
不能直接访问 private基类 private 成员只能通过基类构造函数传递
构造顺序基类 → 派生类;析构顺序相反
自定义复制构造必须在初始化列表中调用 Base(d)
自定义赋值运算符必须显式调用 Base::operator=(d)