C++ 构造函数调用顺序以及什么是虚析构函数?为什么需要它?

✅1. 构造函数调用顺序(完整版本)

  1. 基类构造函数
    • 如果没有显式写初始化列表,默认调用基类的默认构造函数
    • 如果初始化列表中显式调用了某个基类构造函数,则用该构造函数。
  2. 成员变量构造 (按照它们在类中声明的顺序不是初始化列表顺序)。
  3. 派生类构造函数体执行

💡 例子演示:

cpp 复制代码
#include <iostream>

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

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

class Derived : public Base {
    Member m; // 成员变量
public:
    Derived() { std::cout << "Derived constructor\n"; }
};
int main() {
    Derived d;
    return 0;
}

✅ 输出结果:

复制代码
Base constructor
Member constructor
Derived constructor

🔄 调用顺序解释:

步骤 执行的构造函数 原因
1 Base() 基类构造函数最先执行
2 Member() 成员变量构造,按声明顺序
3 Derived() 构造函数体 最后才进入子类构造函数的函数体

🧠 小贴士

  • 成员变量构造顺序只跟它们在类里出现的顺序有关,跟你写在初始化列表里的顺序无关。
  • 构造顺序是:"从外到里" ,析构顺序则是反过来:"从里到外"

2.什么是虚析构函数?为什么需要它?

回答要点:

  • 定义 :在基类中将析构函数声明为virtual,以确保通过基类指针删除派生类对象时,能正确调用派生类的析构函数。

  • 很重要!!!如果一个类打算被继承,一定要让它的析构函数为 virtual

  • 用途:

    • 防止内存泄漏。
    • 确保派生类的资源被正确释放。
  • 不使用虚析构函数的风险:

    • 仅调用基类析构函数,导致派生类资源未释放。

示例:

如果BaseA的析构不写成虚析构,则主函数开辟子类对象赋值给基类指针,以后delete基类指针的时候会发现没有析构子类

cpp 复制代码
class BaseA{
public:
    BaseA(std::string name):_name(name){
        std::cout << "BaseA()" << std::endl;
    }

    ~BaseA(){
        std::cout << "~BaseA()" << std::endl;
    }

private:
    std::string _name;
};

class DerivedA: public BaseA {
public:
    DerivedA(std::string name,std::string num) :
    BaseA(name), _num(num) {
        std::cout << "DerivedA()" << std::endl;
    }

    ~DerivedA(){
        std::cout << "~DerivedA()" << std::endl;
    }
private:
   std::string _num;
};

主函数回收内存

cpp 复制代码
BaseA* base = new DerivedA("zack","1002");
delete base;

会看到只调用了基类BaseA的析构函数。

当BaseA的析构改为虚析构的时候,才会回收子类DerivedA

cpp 复制代码
class BaseA{
public:
    BaseA(std::string name):_name(name){
        std::cout << "BaseA()" << std::endl;
    }

    virtual ~BaseA(){
        std::cout << "~BaseA()" << std::endl;
    }

private:
    std::string _name;
};
相关推荐
智者知已应修善业3 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
云泽8084 小时前
C++11 核心特性全解:列表初始化、右值引用与移动语义实战
开发语言·c++
AI进化营-智能译站5 小时前
ROS2 C++开发系列12-用多态与虚函数构建可扩展的ROS2机器人行为模块
开发语言·c++·ai·机器人
Morwit5 小时前
QML组件之间的通信方案(暴露子组件)
c++·qt·职场和发展
qeen875 小时前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
图码6 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
handler016 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
zhouwy1136 小时前
Linux进程与线程编程详解
linux·c++
A7bert7777 小时前
【YOLOv8pose部署至RDK X5】模型训练→转换bin→Sunrise 5部署
c++·python·深度学习·yolo·目标检测
li1670902707 小时前
第二十七章:智能指针
c语言·数据结构·c++·visual studio