我们都知道,在基类中定义虚函数的目的是允许派生类拥有相同接口却可以有不同的实现,通过对象的指针或引用来访问虚函数可以实现运行时的多态。这么说来,在派生类中重定义(override)虚函数是没有任何问题的。那么,可以重定义基类中的非虚函数吗?

答案是:技术上你可以这样做(至少编译器不会报错),但是绝大多数情况下不应该做。

class Base
{public:void f() { cout << "Base::f()" << endl; }
};class Derived: public Base
{public:void f() { cout << "Derived::f()" << endl; }
};int main()
{Derived d;Base *pb = &d;// Base::f()pb->f();Derived *pd = &d;// Derived::f()pd->f();
}

上面的代码有一个诡异的行为:对同一个派生类对象调用同样的函数,返回的结果是不一样的。这是因为普通的非虚函数体在编译期就与函数调用绑定,指针的类型决定了哪个函数被调用。通过Base调用的f一定是基类的,而通过Derived调用的f一定是派生类的。
从面向对象的角度来说,在派生类中重定义基类中的非虚函数可能会违反公有继承Is-A的关系。公有继承是说每一个派生类对象都可以被当做基类对象来处理。基类的每一个接口和不变量派生类也有。而非虚函数的具体实现是类不变量的一部分。如果重定义了非虚函数,类不变量就可能被打破,派生类对象将不再是基类对象(当通过指向派生类对象的指针访问f时)。

很少情况下,需要重定义非虚函数。一个特例是为了解决私有继承中的名字隐藏问题。在私有继承中,基类的公有函数在派生类中都是私有,如果派生类想要继承基类的某个接口,可以使用所谓的forwarding function。即通过定义一个与基类一模一样的函数,它的实现仅仅是调用基类的对应函数。注意,使用using语句是不可行的,它会把同名的所有重载函数(f()与f(int))都一起导入派生类,参见:C++名字隐藏对公有继承的影响

class Base
{public:f();f(int i);
};class Derived: private Base
{public:// forwarding functionf() { Base::f(); }
};

小结:
绝大多数情况下不要重新定义基类的非虚函数,那样会打破公有继承Is-A的关系,而且行为诡异。

避免在派生类中重新定义基类的非虚函数相关推荐

  1. PetShop 4.0知识点:base 关键字用于从派生类中访问基类的成员

    //base 关键字用于从派生类中访问基类的成员: //调用基类上已被其他方法重写的方法. //指定创建派生类实例时应调用的基类构造函数. //基类访问只能在构造函数.实例方法或实例属性访问器中进行. ...

  2. 在派生类中引发基类事件

    1.  在创建基类时,若涉及到事件,事件是特殊类型的委托,只可以从声明它们的类中调用,派生类无法直接调用基类中声明的事件,但是在多数情况,会需要允许派生类调用基类事件,这时,可以再包含该事件的基类中创 ...

  3. 在c++中,如果派生类没有重写基类中对应virtual函数会怎样?

    在c++中,如果一个派生类没有重写基类中对应的虚函数,那么在派生类的构造函数中依然会创建虚指针,但是该虚指针指向的是基类的虚表. #include <iostream> #include ...

  4. [建立基类Building,作为楼房类,这个基类中包含楼房层数、房间数、楼房总面积等。再建立派生类Home_Arch、Office_Building和Hospital,分别作为住宅楼类、办公楼类和医院

    [建立基类Building,作为楼房类,这个基类中包含楼房层数.房间数.楼房总面积等.再建立派生类Home_Arch.Office_Building和Hospital,分别作为住宅楼类.办公楼类和医院 ...

  5. C++将派生类赋值给基类(向上转型)(一)

    在 C/C++ 中经常会发生数据类型的转换,例如将 int 类型的数据赋值给 float 类型的变量时,编译器会先把 int 类型的数据转换为 float 类型再赋值:反过来,float 类型的数据在 ...

  6. C++派生类对象和基类对象赋值

    在C++中,我们允许 将派生类对象赋给基类对象.(不允许将基类对象赋给派生类对象) 只会将基类对象成员赋值 用基类指针指向派生类对象.(不允许用派生类指针指向基类对象) 基类指针只能操作基类中的成员 ...

  7. T5 根据派生类写出基类(Java) (10分)

    6-1 根据派生类写出基类(Java) (10分) 裁判测试程序样例中展示的是一段定义基类People.派生类Student以及测试两个类的相关Java代码,其中缺失了部分代码,请补充完整,以保证测试 ...

  8. PTA 6-2 根据派生类写出基类(Java)

    6-2 根据派生类写出基类(Java) 裁判测试程序样例中展示的是一段定义基类People.派生类Student以及测试两个类的相关Java代码,其中缺失了部分代码,请补充完整,以保证测试程序正常运行 ...

  9. 指向派生类对象的基类指针与虚函数

    看如下代码: CSales   aSales("崔贤"); CSales* pSales; CWage* pWager; pSales=&aSales; pWager=&a ...

最新文章

  1. 跨进程通信,到底用长连接还是短连接
  2. isamchk mysql_利用Myisamchk对MySQL数据表进行体检
  3. python的字符串类型本质上_4.3Python数据类型(3)之字符串类型
  4. 阿里云——ECS——Linux服务器购买流程——超级细致
  5. Leetcode--3Sum
  6. python打开火狐浏览器打不开网页_PHP让指定网页只能在微信内置浏览器打开 附代码...
  7. Spring boot中使用log4j记录日志
  8. python3怎么做爬虫_Python爬虫入门教程 53-100 Python3爬虫获取三亚天气做旅游参照...
  9. 微服务架构:如何用十步解耦你的系统?
  10. Hi3559av100安装linux,海思hi3559AV100开发板参数规格介绍
  11. 摄像头 保存到外网服务器_直播平台搭建千万不要忽略流媒体服务器的存在
  12. python selenium环境安装及配置_selenium环境配置
  13. 计算机组成原理fpga实验指导书,计算机组成原理 FPGA实验指导书.doc
  14. 发现gmail有邀请权了。有谁需要,先送5个。
  15. VC++ 的 CImageList 绘制背景透明的位图
  16. 使用html查看dicom,使用LEADTOOLS HTML5 Medical Viewer从任何地方查看DICOM图像教程
  17. OpenGL二十面体及多次细分成球体
  18. 打印机 linux 共享文件夹,linux 连接windows打印机
  19. 蕉下招股书里提了26次的DTC,到底是啥?
  20. 经验分享|裸金属服务器部署

热门文章

  1. 在M1芯片arm架构上的mac安装origin和materials studio
  2. matlab中的导函数驻点,[MATLAB基础] 求驻点
  3. Qt/C++编写安防视频监控系统48-视频参数
  4. Android浏览器网络异常,Android调用手机浏览器打开某网页出现异常情况
  5. CentOS 7.3 x64系统vsftpd的安装和配置
  6. MSP430定时器、中断
  7. 21省市物理英才齐聚厦门 激发科学探究兴趣
  8. 通信中隧道技术的解释
  9. unicode什么意思中文_Unicode 和 UTF-8 有什么区别?
  10. 2022如何可以用Python同时抓取多个站点