c++ 类继承中的构造函数、拷贝控制成员与析构函数行为详解

C++ 类继承中的构造函数、拷贝控制成员与析构函数行为详解


1. 构造函数调用规则
1.1 默认构造函数
  • 隐式调用:若派生类未显式定义构造函数,合成的默认构造函数会隐式调用 基类的默认构造函数
  • 错误示例:基类没有默认构造函数时,编译失败。
class Base {
public:
    Base(int x) {} // 无默认构造函数
};

class Derived : public Base {
    // 隐式生成 Derived(),尝试调用 Base(),但 Base 无默认构造函数,编译错误!
};
1.2 其他构造函数
  • 显式调用基类构造函数:若派生类构造函数未显式调用基类构造函数,编译器会尝试调用基类的 默认构造函数
class Base {
public:
    Base() { std::cout << "Base()\n"; }
    Base(int x) { std::cout << "Base(int)\n"; }
};

class Derived : public Base {
public:
    Derived(int x) { 
        // 隐式调用 Base(),输出 "Base()"
        std::cout << "Derived(int)\n"; 
    }
    Derived(int x, int y) : Base(x) { 
        // 显式调用 Base(int),输出 "Base(int)"
        std::cout << "Derived(int, int)\n"; 
    }
};

int main() {
    Derived d1(10);     // 输出 Base() → Derived(int)
    Derived d2(10, 20); // 输出 Base(int) → Derived(int, int)
}

2. 拷贝控制成员
2.1 拷贝构造函数
  • 隐式调用基类拷贝构造函数:派生类合成的拷贝构造函数会调用基类的拷贝构造函数。
class Base {
public:
    Base() = default;
    Base(const Base&) { std::cout << "Base copy\n"; }
};

class Derived : public Base {
    // 隐式生成 Derived(const Derived&),调用 Base(const Base&)
};

int main() {
    Derived d1;
    Derived d2(d1); // 输出 "Base copy"
}
2.2 赋值运算符
  • 隐式调用基类赋值运算符:派生类合成的赋值运算符会调用基类的赋值运算符。
class Base {
public:
    Base& operator=(const Base&) { 
        std::cout << "Base assignment\n"; 
        return *this;
    }
};

class Derived : public Base {
    // 隐式生成 operator=,调用 Base::operator=
};

int main() {
    Derived d1, d2;
    d1 = d2; // 输出 "Base assignment"
}
2.3 显式定义时的注意事项
  • 必须显式调用基类成员:若显式定义拷贝构造函数或赋值运算符,需手动调用基类对应函数。
class Base { /* ... */ };

class Derived : public Base {
public:
    Derived(const Derived& rhs) : Base(rhs) { // 显式调用基类拷贝构造函数
        // 拷贝派生类成员
    }
    Derived& operator=(const Derived& rhs) {
        Base::operator=(rhs); // 显式调用基类赋值运算符
        // 赋值派生类成员
        return *this;
    }
};

3. 析构函数
3.1 隐式调用基类析构函数
  • 销毁顺序:派生类析构函数执行完毕后,自动调用基类析构函数。
class Base {
public:
    ~Base() { std::cout << "~Base()\n"; }
};

class Derived : public Base {
public:
    ~Derived() { std::cout << "~Derived()\n"; }
};

int main() {
    Derived d; 
} // 输出 ~Derived() → ~Base()
3.2 基类析构函数必须为虚函数
  • 关键规则:若通过基类指针删除派生类对象,基类析构函数必须为虚函数,否则导致 资源泄漏
class Base {
public:
    virtual ~Base() { std::cout << "~Base()\n"; } // 虚析构函数
};

class Derived : public Base {
public:
    ~Derived() { std::cout << "~Derived()\n"; }
};

int main() {
    Base* ptr = new Derived();
    delete ptr; // 正确调用 ~Derived() → ~Base()
}

4. 构造与析构顺序
4.1 构造顺序
  • 基类 → 成员对象 → 派生类
class Member {
public:
    Member() { std::cout << "Member()\n"; }
};

class Base {
public:
    Base() { std::cout << "Base()\n"; }
};

class Derived : public Base {
    Member m;
public:
    Derived() { std::cout << "Derived()\n"; }
};

int main() {
    Derived d; 
} // 输出 Base() → Member() → Derived()
4.2 析构顺序
  • 派生类 → 成员对象 → 基类
// 使用上述类定义
int main() {
    Derived d;
} // 输出 Derived() → Member() → Base()
          ↓ 析构时 ↓
       ~Derived()~Member()~Base()

5. 显式定义特殊成员函数
5.1 必须显式调用基类成员的情况
  • 自定义拷贝构造函数
class Base { /* ... */ };

class Derived : public Base {
public:
    Derived(const Derived& rhs) 
        : Base(rhs) { // 必须显式调用基类拷贝构造函数
        // 拷贝派生类成员
    }
};
  • 自定义赋值运算符
class Derived : public Base {
public:
    Derived& operator=(const Derived& rhs) {
        Base::operator=(rhs); // 必须显式调用基类赋值运算符
        // 赋值派生类成员
        return *this;
    }
};
  • 自定义移动操作(C++11):
class Derived : public Base {
public:
    Derived(Derived&& rhs) 
        : Base(std::move(rhs)) { // 显式移动基类部分
        // 移动派生类成员
    }
};

总结

  1. 构造顺序:基类 → 成员对象 → 派生类。
  2. 析构顺序:派生类 → 成员对象 → 基类。
  3. 隐式调用规则
    • 默认构造函数调用基类默认构造函数。
    • 拷贝构造函数调用基类拷贝构造函数。
    • 赋值运算符调用基类赋值运算符。
  4. 显式定义时的要求:需手动调用基类对应函数。
  5. 基类析构函数必须为虚函数,避免资源泄漏。

示例代码整合

#include <iostream>

class Base {
public:
    Base() { std::cout << "Base()\n"; }
    Base(const Base&) { std::cout << "Base copy\n"; }
    virtual ~Base() { std::cout << "~Base()\n"; }
    Base& operator=(const Base&) { 
        std::cout << "Base assignment\n"; 
        return *this;
    }
};

class Member {
public:
    Member() { std::cout << "Member()\n"; }
    ~Member() { std::cout << "~Member()\n"; }
};

class Derived : public Base {
    Member m;
public:
    Derived() { std::cout << "Derived()\n"; }
    Derived(const Derived& rhs) : Base(rhs), m(rhs.m) { 
        std::cout << "Derived copy\n"; 
    }
    Derived& operator=(const Derived& rhs) {
        Base::operator=(rhs);
        m = rhs.m;
        std::cout << "Derived assignment\n"; 
        return *this;
    }
    ~Derived() { std::cout << "~Derived()\n"; }
};

int main() {
    Derived d1;          // 构造顺序:Base → Member → Derived
    Derived d2(d1);      // 拷贝构造:Base copy → Member copy → Derived copy
    d1 = d2;             // 赋值操作:Base assignment → Derived assignment
} 
// 析构顺序:~Derived → ~Member → ~Base(两次)

输出

Base()
Member()
Derived()
Base copy
Member copy
Derived copy
Base assignment
Derived assignment
~Derived()
~Member()
~Base()
~Derived()
~Member()
~Base()
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值