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

EffectiveC++读书笔记——item36(不要重定义继承的非虚拟函数)

1. 重定义继承的非虚拟函数导致行为差异

假设存在类B和从其公有继承的类D,类B中有一个公有成员函数mf

class B {
public:
    void mf();
};
class D : public B {
public:
    void mf(); 
};

当使用D类型的对象x,通过指向xB类型指针pBD类型指针pD调用mf函数时:

D x; 
B *pB = &x; 
pB->mf(); 
D *pD = &x; 
pD->mf(); 

mf为非虚拟函数,pB->mf()调用的是B::mfpD->mf()调用的是D::mf,这是因为非虚拟函数是静态绑定的,调用的函数取决于指针的声明类型。而虚拟函数是动态绑定的,不会出现这种情况,若mf为虚拟函数,通过pBpD调用mf都会导致D::mf的调用。

2. 禁止重定义的理论依据

  • 公有继承意味着 “is - a” 关系:即每个D对象都是一个B对象,适用于B对象的特性也应适用于D对象。
  • 非虚拟函数设定 “超越特殊化的不变量”:从B继承的类必须同时继承mf的接口和实现。

D重定义mf,会产生矛盾:

  • D确实需要不同于Bmf实现,且B对象无论如何特殊都必须使用Bmf的实现,那么 “每个D都是一个B” 就不成立,D不应从B公有继承。
  • D必须从B公有继承,且D需要不同于Bmf实现,那么 “mf反映B的超越特殊化的不变量” 就不成立,mf应是虚拟函数。
  • 若每个D确实都是一个B,且mf相当于B的超越特殊化的不变量,那么D就不应重定义mf

3. 与 Item 7 的联系

Item 7 中解释了多态基类的析构函数应该是虚拟的,若在多态基类中声明非虚拟析构函数,派生类总会重定义继承的非虚拟析构函数,这其实是本文所述规则的一个特殊情况,因该情况重要所以单独成篇。

4. 总结

在 C++ 中,绝不要重定义一个通过继承得到的非虚拟函数,否则会导致对象行为不协调,且违反公有继承和非虚拟函数的设计原则。


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

相关文章:

  • OSPF高级特性(3):安全特效
  • 未来趋势系列 篇一(加更四):DeepSeek题材解析和股票梳理
  • 使用stm32控制esp01s
  • 接口测试Day12-持续集成、git简介和安装、Gitee远程仓库、jenkins集成
  • Java+vue前后端分离项目集群部署
  • Go语言的内存分配原理
  • vue中使用lodash的debounce(防抖函数)
  • 如何安装和运行Zonos:详细步骤指南
  • ES6具体有什么
  • 爬虫瑞数5.5案例:某钢材交易官网(面向对象补环境)
  • Docker 部署 MySQL-5.7 单机版
  • 13.13 Flask Web Server 架构设计与生产级实现指南:从 RESTful API 开发到高并发优化
  • 【NXP i.MX6ULL 使用】IMX6Y2C-512M-EMMC 设备树配置文档
  • Windows上在Qt中快速配置OpenCV库(最简单教程)
  • ffmpeg所有版本下载地址
  • PyTorch Lightning LightningDataModule 介绍
  • 【Linux】nmcli命令详解
  • 2025.1.8(qt图形化界面之消息框)
  • Win10环境借助DockerDesktop部署最新MySQL9.2
  • JVM速成=。=
  • 【java】java学习笔记之java 进阶
  • CCF-CSP第34次认证第二题——矩阵重塑(其二)【需反复思考学习!!!】
  • DeepSeek 模型的本地部署指南
  • Ubuntu 上安装和配置 Nexus Repository Manager
  • 相机模数转换
  • AWTK-WEB 快速入门(4) - JS Http 应用程序