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

Effective C++ 条款36:绝不重新定义继承而来的 non-virtual 函数

文章目录

    • 条款36:绝不重新定义继承而来的 non-virtual 函数
      • 问题说明
        • 示例:重新定义 `non-virtual` 函数
      • 解析
      • 为什么避免重新定义 `non-virtual` 函数
      • 正确的设计方式
        • 示例:使用 `virtual` 函数实现多态
      • 总结

条款36:绝不重新定义继承而来的 non-virtual 函数

在 C++ 中,non-virtual 函数并不支持动态绑定。这意味着即使派生类重新定义了基类的 non-virtual 函数,调用函数时的行为取决于调用对象的静态类型,而非运行时的动态类型。

问题说明

当重新定义继承而来的 non-virtual 函数时,程序的行为可能会变得难以预测,尤其是通过基类指针或引用调用这些函数时,可能导致意外的结果。

示例:重新定义 non-virtual 函数
class Base {
public:
    void nonVirtualFunc() const {
        std::cout << "Base::nonVirtualFunc" << std::endl;
    }
};

class Derived : public Base {
public:
    void nonVirtualFunc() const { // 不推荐,行为难以预测
        std::cout << "Derived::nonVirtualFunc" << std::endl;
    }
};

int main() {
    Base* b = new Derived;
    b->nonVirtualFunc(); // 输出: Base::nonVirtualFunc

    Derived d;
    d.nonVirtualFunc();  // 输出: Derived::nonVirtualFunc

    delete b;
    return 0;
}

解析

  1. 基类指针或引用 调用 non-virtual 函数时,只会调用基类的实现,而不会调用派生类的重定义版本。

    • 在上例中,通过基类指针 b 调用 nonVirtualFunc,实际调用的是 Base::nonVirtualFunc,而非 Derived::nonVirtualFunc
  2. 直接调用派生类对象的方法 则会调用派生类版本的函数。

    • 在上例中,通过派生类对象 d 调用 nonVirtualFunc,调用的是 Derived::nonVirtualFunc

为什么避免重新定义 non-virtual 函数

  • 意图混淆:重新定义 non-virtual 函数的代码容易让人误以为这些函数是多态的。
  • 行为不一致:通过基类指针或引用调用时的行为与直接调用派生类对象的方法不同,可能导致潜在的错误。
  • 设计问题:继承关系中的重定义通常表明代码设计存在问题。如果需要重定义,通常应该将函数声明为 virtual

正确的设计方式

如果需要多态行为,应该将函数声明为 virtual;如果不需要多态行为,则应该避免重定义继承而来的 non-virtual 函数。

示例:使用 virtual 函数实现多态
class Base {
public:
    virtual void virtualFunc() const {
        std::cout << "Base::virtualFunc" << std::endl;
    }
};

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

int main() {
    Base* b = new Derived;
    b->virtualFunc(); // 输出: Derived::virtualFunc

    delete b;
    return 0;
}

总结

  • 不要重新定义继承而来的 non-virtual 函数,因为它不会实现多态行为。
  • 如果需要多态行为,请使用 virtual 函数。
  • 如果确实需要防止某些函数被派生类覆盖,可以将它们声明为 final 或非虚函数,并明确设计接口。

通过清晰区分 virtualnon-virtual 函数的用途,可以避免混乱和潜在的错误。


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

相关文章:

  • Nginx - 整合lua 实现对POST请求的参数拦截校验(不使用Openresty)
  • GDPU 数据库原理 期末复习
  • 注入少量可学习的向量参数: 注入适配器IA3
  • 丢弃法hhhh
  • Unity 对Sprite或者UI使用模板测试扣洞
  • 算法题(23):只出现一次的数字
  • 钉钉h5微应用鉴权
  • 数仓建模:如何进行实体建模?
  • 数据结构之线性表之链表(附加一个考研题)
  • docker学习记录-部署若依springcloud项目
  • 4.3 数据库HAVING语句
  • 精品方案推介:649页智慧水务大数据云平台解决方案
  • 【JMeter详解】
  • 32单片机从入门到精通之硬件架构——内核与外设(一)
  • 014-spring-aop的原理
  • Android 转场动画合集
  • WebSocket 的封装使用
  • E卷-恢复数字序列(100分)
  • C语言程序设计:程序设计和C语言
  • 如何判断一个学术论文是否具有真正的科研价值?ChatGPT如何提供帮助?
  • 抽象工厂模式详解
  • 初识 Conda:一站式包管理和环境管理工具
  • Unity3D 基于GraphView实现的节点编辑器框架详解
  • es6 字符串每隔几个中间插入一个逗号
  • 【Cursor编辑器】自用经验和实操(迭代更新)
  • 【MySQL】搞懂mvcc、read view:MySQL事务原理深度剖析