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

Effective_C++09: 绝不在构造和析构过程中调用virtual函数

Effective C++ 条款09:绝不在构造和析构过程中调用virtual函数


核心思想在构造和析构期间不要调用virtual函数,因为这类调用不会下降至派生类(比起当前执行构造函数和析构函数的那层)。

⚠️ 1. 问题场景:基类构造中调用虚函数
#include <iostream>
class Transaction {
public:Transaction() {logTransaction(); // 构造函数中调用虚函数}virtual void logTransaction() const {std::cout << "Base transaction logged\n";}
};class BuyTransaction : public Transaction {
public:virtual void logTransaction() const override {std::cout << "Buy transaction logged\n";}
};int main() {BuyTransaction b; // 期望调用BuyTransaction的logTransactionreturn 0;
}

输出

Base transaction logged

原因

  • BuyTransaction构造时,首先调用基类Transaction构造函数
  • 此时对象类型被视为Transaction而非BuyTransaction
  • 虚函数机制不会下降到派生类实现

2. 解决方案:非虚接口模式
(1) 静态方法传递信息(⭐️推荐)
class Transaction {
public:explicit Transaction(const std::string& logInfo) {logTransaction(logInfo); // 非虚函数}void logTransaction(const std::string& logInfo) const {std::cout << logInfo << std::endl;}
};class BuyTransaction : public Transaction {
public:BuyTransaction() : Transaction(createLogString()) {} // 传递信息private:static std::string createLogString() { // 静态方法安全return "Buy transaction logged";}
};
(2) 初始化列表传递信息
class BuyTransaction : public Transaction {
public:BuyTransaction() : Transaction("Buy transaction logged") {} // 直接传递
};

🔍 3. 关键原则
场景操作原因
构造/析构中需定制行为通过参数传递信息,调用非虚函数虚函数机制在构造/析构期间不完整
派生类需提供初始化信息使用静态方法生成信息(可访问类静态成员)避免使用未初始化的成员变量
基类构造函数需要类型相关信息在派生类构造函数初始化列表中传递确保信息在基类构造前可用
避免在析构函数中调用虚函数析构顺序与构造相反,同样虚函数机制不完整防止调用已被销毁的派生类成员

⚠️ 4. 错误案例:派生类析构中的虚函数
class Base {
public:virtual ~Base() {cleanup(); // 基类析构中调用虚函数}virtual void cleanup() {std::cout << "Base cleanup\n";}
};class Derived : public Base {
public:~Derived() {// 隐式调用Base::~Base()}virtual void cleanup() override {std::cout << "Derived cleanup\n";}
};int main() {Derived d; // 析构时调用Base::cleanup()而非Derived::cleanup()return 0;
}

输出

Base cleanup

结论

  • 析构顺序:先派生类析构 → 再基类析构
  • 基类析构执行时,对象已被视为基类类型

💎 总结:构造析构虚函数三原则

  1. 绝对避免
    构造和析构期间绝不直接调用虚函数。

  2. 信息传递
    通过参数将定制信息传递给基类的非虚函数:

    class Base {
    public:Base(const std::string& info) { nonVirtualInit(info); // 非虚函数}
    };class Derived : public Base {
    public:Derived() : Base(generateInfo()) {}
    private:static std::string generateInfo() { return "Custom data"; }
    };
    
  3. 静态方法优先
    在派生类中使用静态方法生成信息,避免访问未初始化的成员变量。

http://www.dtcms.com/a/305268.html

相关文章:

  • 【解决办法】pip install albumentations安装下载遇19kB/s超级慢细水管
  • 无代码测试平台ATECLOUD全场景测试方案
  • Java中Boolean.getBoolean方法误用与修复
  • 【监控】非IP监控系统改造IP监控系统
  • 中科米堆CASAIM空调扇叶自动蓝光三维测量解决方案
  • <RT1176系列12>DMAMUX入门级应用和DMAMUX MAP表
  • Linux定时器和时间管理源码相关总结
  • 【Unity编辑器扩展】Unity场景选择工具 - ScenesChooseTool 使用指南
  • 项目历程—生命数组游戏(两版本)
  • 智源研究院发布数据魔方,以智能化自定义方式重构模型训练数据供给范式
  • 两数之和(每天刷力扣hot100系列)
  • JDK17 新特性跟学梳理
  • Java注解全面解析与应用实战
  • Redis 跨主机连接超时分析:从网络波动到架构优化
  • 关于算法的一些思考
  • 基于springboot的零食商城的设计与实现/零食销售系统的设计与实现
  • 基于Matlab图像处理的静态雨滴去除与质量评估系统
  • JAVA第五学:方法的使用 调试讲解
  • RAG实战指南 Day 26:RAG系统评估指标与方法
  • 2025年06月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • R语言中 read.table 和 read.delim 之间的区别
  • vue中使用wavesurfer.js绘制波形图和频谱图
  • 数学建模算法-day[14]
  • Java中写文件的显示大小实时性
  • 深入理解 boost::lock_guard<boost::mutex>
  • mybatis-plus由mysql改成达梦数据库
  • 【Linux】重生之从零开始学习运维之Mysql事务
  • Python day28
  • 破解企业无公网 IP 难题:可行路径与实现方法?
  • Three.js 渲染优化处理