当前位置: 首页 > web >正文

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

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

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

💡 例子演示:

#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

🔄 调用顺序解释:

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

🧠 小贴士

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

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

回答要点:

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

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

  • 用途:

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

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

示例:

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

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;
};

主函数回收内存

BaseA* base = new DerivedA("zack","1002");
delete base;

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

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

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;
};
http://www.xdnf.cn/news/693.html

相关文章:

  • Ubuntu下安装和卸载MySQL
  • 简单使用MCP
  • PCA 降维实战:从原理到电信客户流失数据应用
  • 一键升级OpenSSH/OpenSSL修复安全漏洞
  • 【LINUX操作系统】线程基础与分页式存储管理
  • C++初阶-类和对象(中)
  • 【数据分析实战】使用 Matplotlib 绘制散点图
  • Android音视频开发
  • 【网络】通过Samba实现Window挂在Linux服务器路径
  • 【Windows10下PP-OCRv4部署指南‌】
  • 云点数据读写
  • 33-公交车司机管理系统
  • Kubernetes控制平面组件:调度器Scheduler(二)
  • MySQL:9.表的内连和外连
  • 字节头条golang二面
  • 基于Python的推荐算法的电影推荐系统的设计
  • 【深度学习入门_NLP自然语言处理】序章
  • node.js|环境部署|源码编译高版本的node.js
  • 【实战中提升自己】内网安全部署之端口隔离与MAC地址认证
  • 20.Chromium指纹浏览器开发教程之屏幕信息指纹定制
  • LeetCode 打家劫舍+删除并获得点数
  • HTTP 2.0 和 3.0 的区别
  • 【嵌入式人工智能产品开发实战】(二十一)—— 政安晨:源码搭建小智AI嵌入式终端的后端服务(服务器)环境 - 助力嵌入式人工智能开发
  • Leetcode 3523. Make Array Non-decreasing
  • 【Vulkan 入门系列】创建交换链、图像视图和渲染通道(四)
  • Linux 常用指令用户手册
  • MySQL-锁机制3-意向共享锁与意向排它锁、死锁
  • 量子计算与经典计算融合:开启计算新时代
  • Spring Boot集成MongoDB及实战技巧与性能调优
  • 为何AI发展的终极战场将是Agent的竞争?