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

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

文章目录

    • 条款 09:绝不在构造和析构过程中调用 virtual 函数
      • 关键原则
      • 示例问题:构造期间调用 `virtual` 函数
      • 设计建议
      • 总结

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

关键原则

  • 避免构造或析构期间调用 virtual 函数
    在构造函数或析构函数内部调用 virtual 函数,只会调用当前类版本的函数,而不会调用 derived class 中的覆写版本。

  • 构造和析构期间的对象行为
    当构造函数执行时,对象尚未完全构造完成;当析构函数执行时,派生类的成员可能已经被销毁。这导致 virtual 函数无法正确工作。


示例问题:构造期间调用 virtual 函数

以下代码演示了在构造期间调用 virtual 函数的问题:

class Base {
public:
  Base() { call(); }  // 在构造函数中调用 virtual 函数
  virtual void call() const {
    std::cout << "Base::call" << std::endl;
  }
};

class Derived : public Base {
public:
  Derived() {}
  virtual void call() const override {
    std::cout << "Derived::call" << std::endl;
  }
};

int main() {
  Derived d;  // 输出:Base::call
  return 0;
}

解释:

  • 在构造 Derived 对象时,Base 的构造函数调用了 call 函数。
  • 因为 Derived 的部分尚未完成初始化,调用的是 Base::call 而不是 Derived::call

设计建议

  1. 避免构造或析构期间调用 virtual 函数
    构造和析构期间对象处于特殊状态,避免不确定性。

  2. 延迟行为到完全初始化后执行
    使用辅助函数显式触发需要派生类支持的行为,例如:

    class Base {
    public:
      Base() {}
      void init() { call(); }  // 提供显式调用函数
      virtual void call() const {
        std::cout << "Base::call" << std::endl;
      }
    };
    
    class Derived : public Base {
    public:
      Derived() {}
      virtual void call() const override {
        std::cout << "Derived::call" << std::endl;
      }
    };
    
    int main() {
      Derived d;
      d.init();  // 显式触发行为
      return 0;
    }
    
  3. 以 non-virtual 函数完成构造和析构期间的任务
    通过 non-virtual 函数实现相关任务,避免对未完全构造或已销毁部分的调用。


总结

  • 在构造和析构期间调用 virtual 函数是危险且不可预测的。
  • 明确区分构造/析构期间和对象完全构造后的行为。
  • 借助显式函数调用或 non-virtual 函数解决该问题。

http://www.kler.cn/a/454373.html

相关文章:

  • 数据结构(Java)——链表
  • Java中处理if-else的几种高级方法
  • scala基础学习(数据类型)-数组
  • 云计算时代携程的网络架构变迁
  • 五十七:RST_STREAM帧及常见错误码
  • 《迁移学习与联邦学习:推动人工智能发展的关键力量》
  • python操作Elasticsearch执行增删改查
  • 十二月第23讲:.NET 9 New features-AOT相关的改进
  • ubuntu搭建redis cluster集群三主三从(从0搭建,小白也会,不啰嗦)
  • (十)Ubuntu 20.04+akiaaa大神 Stable Diffusion整合包 AI绘画教程-外挂VAE模型等快捷设置教程
  • HarmonyOS NEXT 实战之元服务:静态案例效果---电动车电池健康状况
  • DPO(Direct Preference Optimization)算法解释:中英双语
  • 嵌入式学习-QT-Day11
  • .NET Core 中使用 C# 获取Windows 和 Linux 环境兼容路径合并
  • springcloud依赖
  • MongoDB 创建用户、User、Role 相关 操作
  • 机器学习基础算法 (二)-逻辑回归
  • 【LeetCode 面试经典150题】详细题解之哈希表篇
  • QT-【常用容器类】-QList类 QLinkedList类
  • stp生成树协议
  • Apache Solr XXE(CVE-2017-12629)--vulhub
  • 低代码开源项目Joget的研究——Joget7社区版安装部署
  • 寻找适合小户型的开源知识库open source knowledge base之路
  • ModbusTCP转Profinet:ABB机器人与PLC的高效连接
  • 《解锁 Python 数据挖掘的奥秘》
  • easegen将教材批量生成可控ppt课件方案设计