派生类构造函数(第 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) |