C++ override及虚函数的讲解
C++11 之 override
1 公有继承
公有继承包含两部分:一是 "接口" (interface),二是 "实现" (implementation)
基类 Shape 中,三个成员函数,代表三种继承方式:
class Shape { public:virtual void Draw() const = 0; // 1) 纯虚函数 virtual void Error(const std::string& msg); // 2) 普通虚函数 int ObjectID() const; // 3) 非虚函数 };class Rectangle: public Shape { ... }; class Ellipse: public Shape { ... };
1.1 纯虚函数 (pure virtual)
纯虚函数,表示继承的只是基类成员函数的接口,且要在派生类中重写该函数的实现
Shape *ps1 = new Rectangle; ps1->Draw(); // calls Rectangle::Draw Shape *ps2 = new Ellipse; ps2->Draw(); // calls Ellipse::Draw
若想调用基类的 Draw(),须加上 类作用域操作符 ::
ps1->Shape::Draw(); // calls Shape::draw
1.2 普通虚函数
普通虚函数,对应在基类中定义一个缺省的实现 (default implementation),表示继承的是基类成员函数的接口和缺省的实现,由派生类自行选择是否重写该函数。
实际上,允许普通虚函数同时继承接口和缺省实现是危险的。 如下, ModelA 和 ModelB 是 Airplane 的两种飞机类型,且二者的飞行方式完全相同
class Airplane { public:virtual void Fly(const Airport& destination); }; class ModelA: public Airplane { ... }; class ModelB: public Airplane { ... };
这是典型的面向对象设计,两个类共享一个特性 -- Fly,则 Fly 可在基类中实现,并由两个派生类继承之
现增加一个新的飞机型号 ModelC,其飞行方式与 ModelA,ModelB 并不相同,假如不小心忘了在 ModelC 中重写新的 Fly 函数
class ModelC: public Airplane {... // no fly function is declared };
则调用 ModelC 中的 fly 函数,就是调用 Airplane::Fly,但是 ModelC 的飞行方式和缺省的并不相同
Airplane *pa = new ModelC; pa->Fly(Qingdao); // calls Airplane::fly!
这就是前面所说的,普通虚函数同时继承接口和缺省实现是危险的,最好是基类中实现缺省行为 (behavior),但只有在派生类要求时才提供该缺省行为
1.2.1 方法一
一种方法是 纯虚函数 + 缺省实现,因为是纯虚函数,所以只有接口被继承,其缺省的实现不会被继承。派生类要想使用该缺省的实现,必须显式的调用
class Airplane { public:virtual void Fly(const Airport& destination) = 0; };void Airplane::Fly(const Airport& destination) { // a pure virtual function default code for flying an airplane to the given destination }class ModelA: public Airplane { public:virtual void Fly(const Airport& destination) { Airplane::Fly(destination); } };
这样在派生类 ModelC 中,即使一不小心忘记重写 Fly 函数,也不会调用 Airplane 的缺省实现
class ModelC: public Airplane { public:virtual void Fly(const Airport& destination); };void ModelC::Fly(const Airport& destination) {// code for flying a ModelC airplane to the given destination }
1.2.2 方法二
可以看到,上面问题的关键就在于,一不小心在派生类 ModelC 中忘记重写 fly 函数,C++11 中使用关键字 override,可以避免这样的“一不小心”
1.3 非虚函数
非虚成员函数没有 virtual 关键字,表示派生类不但继承了接口,而且继承了一个强制实现 (mandatory implementation)
既然继承了一个强制的实现,则在派生类中,无须重新定义 (redefine) 继承自基类的成员函数,如下:
使用指针调用 ObjectID 函数,则都是调用的 Shape::ObjectID()
Rectangel rc; // rc is an object of type Rectangle Shape *pB = &rc; // get pointer to rc pB->ObjectID(); // call ObjectID() through pointer Rectangle *pD = &rc; // get pointer to rc pD->ObjectID(); // call ObjectID() through pointer
如果在派生类中重新定义了继承自基类的成员函数 ObjectID 呢?
class Rectangel : public Shape { public:int ObjectID() const; // hides Shape::ObjectID };pB->ObjectID(); // calls Shape::ObjectID() pD->ObjectID(); // calls Rectagle::ObjectID()
此时,派生类中重新定义的成员函数会 “隐藏” (hide) 继承自基类的成员函数
这是因为非虚函数是 “静态绑定” 的,pB 被声明的是 Shape* 类型的指针,则通过 pB 调用的非虚函数都是基类中的,既使 pB 指向的是派生类
与“静态绑定”相对的是虚函数的“动态绑定”,即无论 pB 被声明为 Shape* 还是 Rectangle* 类型,其调用的虚函数取决于 pB 实际指向的对象类型
2 重写 (override)
在 1.2.2 中提到 override 关键字,可以避免派生类中忘记重写虚函数的错误
下面以重写虚函数时,容易犯的四个错误为例,详细阐述之
class Base { public:virtual void mf1() const;virtual void mf2(int x);virtual void mf3() &;void mf4() const; // is not declared virtual in Base };class Derived: public Base { public:virtual void mf1(); // declared const in Base, but not in Derived.virtual void mf2(unsigned int x); // takes an int in Base, but an unsigned int in Derivedvirtual void mf3() &&; // is lvalue-qualified in Base, but rvalue-qualified in Derived.void mf4() const; };
在派生类中,重写 (override) 继承自基类成员函数的实现 (implementation) 时,要满足如下条件:
一虚:基类中,成员函数声明为虚拟的 (virtual)
二容:基类和派生类中,成员函数的返回类型和异常规格 (exception specification) 必须兼容
四同:基类和派生类中,成员函数名、形参类型、常量属性 (constness) 和 引用限定符 (reference qualifier) 必须完全相同
如此多的限制条件,导致了虚函数重写如上述代码,极容易因为一个不小心而出错
C++11 中的 override 关键字,可以显式的在派生类中声明,哪些成员函数需要被重写,如果没被重写,则编译器会报错。
class Derived: public Base { public:virtual void mf1() override;virtual void mf2(unsigned int x) override;virtual void mf3() && override;virtual void mf4() const override; };
这样,即使不小心漏写了虚函数重写的某个苛刻条件,也可以通过编译器的报错,快速改正错误
class Derived: public Base { public:virtual void mf1() const override; // adding "virtual" is OK, but not necessaryvirtual void mf2(int x) override; void mf3() & override;void mf4() const override; };
小结:
1) 公有继承
纯虚函数 => 继承的是:接口 (interface)
普通虚函数 => 继承的是:接口 + 缺省实现 (default implementation)
非虚成员函数 =>继承的是:接口 + 强制实现 (mandatory implementation)
2) 不要重新定义一个继承自基类的非虚函数 (never redefine an inherited non-virtual function)
3) 在声明需要重写的函数后,加关键字 override
参考资料:
<Effective C++_3rd> item 34, item 36
<Effective Modern C++> item 12
关注 - 4
粉丝 - 29
» 下一篇:C++ 之 策略模式
【推荐】Vue.js 2.x 快速入门,大量高效实战示例
【活动】腾讯云 学生专属优惠套餐 多规格选择
· ofo越过山丘
· 360重组议案过关股东大会500亿元资产注入在即
· 美国邮政推出VR应用 但并不是提供有关邮寄信件的信息
· 柳传志撰文:我为湖畔大学正名
· 趣店数据疑似外泄,十万可买百万学生信息
» 更多新闻...
· 关于编程,你的练习是不是有效的?
· 改善程序员生活质量的 3+10 习惯
· NASA的10条代码编写原则
· 为什么你参加了那么多培训,却依然表现平平?
» 更多知识库文章...
公告
园龄:1年9个月
粉丝:29
关注:4
|
|||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
29 | 30 | 31 | 1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 | |||
12 | 13 | 14 | 15 | 16 | 17 | 18 | |||
19 | 20 | 21 | 22 | 23 | 24 | 25 | |||
26 | 27 | 28 | 29 | 30 | 1 | 2 | |||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
搜索
常用链接
- 我的随笔
- 我的评论
- 我的参与
- 最新评论
- 我的标签
我的标签
- OpenCV(10)
- C++(8)
- C++11(5)
- Qt(5)
- Verilog(2)
- 模式识别(2)
- Linux(2)
- Machine Learning(1)
- Deutsch(1)
- 设计模式(1)
- 更多
随笔分类
- 机器视觉(1)
- 逻辑设计(7)
- 软件编程(24)
- 图像处理(10)
- 易北往事(3)
随笔档案
- 2017年9月 (1)
- 2017年8月 (3)
- 2017年7月 (2)
- 2017年6月 (2)
- 2017年5月 (1)
- 2017年2月 (3)
- 2017年1月 (1)
- 2016年11月 (2)
- 2016年10月 (1)
- 2016年9月 (2)
- 2016年8月 (2)
- 2016年7月 (4)
- 2016年6月 (4)
- 2016年5月 (4)
- 2016年4月 (4)
- 2016年3月 (3)
- 2016年2月 (3)
- 2016年1月 (4)
最新评论
- 1. Re:OpenCV 之 编译和配置
- @xiake007生成了,已经更新了新的记录...
- --胡马依北风
- 2. Re:机器视觉 之 齐次坐标
- @胡马依北风lichongbin2004@126.com,谢谢!...
- --lichongbin
- 3. Re:机器视觉 之 齐次坐标
- @lichongbin有电子版,需要的话可留个邮箱,发给你 ......
- --胡马依北风
- 4. Re:机器视觉 之 齐次坐标
- 你给出的这三本参考书哪里有的卖?
- --lichongbin
- 5. Re:OpenCV 之 编译和配置
- 写得真详细,后来问题怎么样了?生成成功了吗?
- --xiake007
阅读排行榜
- 1. C++11 之 override(7926)
- 2. Qt 之 入门例程(4085)
- 3. C++11 之 delete 和 default(3942)
- 4. OpenCV 之 边缘检测(2646)
- 5. OpenCV 之 编译和配置(1941)
- 6. OpenCV 之 霍夫变换(1621)
- 7. OpenCV 之 图像平滑(1575)
- 8. Qt 之 饼图(1561)
- 9. Qt 之 QtConcurrent(1521)
- 10. OpenCV 之 神经网络 (一)(1352)
评论排行榜
- 1. OpenCV 之 编译和配置(3)
- 2. 机器视觉 之 刚体变换(3)
- 3. C++11 之 delete 和 default(2)
- 4. OpenCV 之 图像平滑(2)
- 5. C++ 之 策略模式(1)
推荐排行榜
- 1. C++11 之 scoped enum(4)
- 2. C++ 之 策略模式(4)
- 3. OpenCV 之 图像分割 (一)(4)
- 4. Qt 地址薄 (一) 界面设计(2)
- 5. C++11 之 override(2)
- 6. OpenCV 之 图像平滑(2)
- 7. C++11 之 nullptr(2)
- 8. OpenCV 之 边缘检测(2)
- 9. C++笔记 之 基础回顾(一)(2)
- 10. OpenCV 之 编译和配置(1)
C++ override及虚函数的讲解相关推荐
- C++反汇编第三讲,反汇编中识别虚表指针,以及指向的虚函数地址
C++反汇编第三讲,反汇编中识别虚表指针,以及指向的虚函数地址 讲解之前,了解下什么是虚函数,什么是虚表指针,了解下语法,(也算复习了) 开发知识为了不码字了,找了一篇介绍比较好的,这里我扣过来了,当 ...
- [C++] - 纯虚函数 抽象基类 接口类
翻译自:https://www.learncpp.com/cpp-tutorial/126-pure-virtual-functions-abstract-base-classes-and-inter ...
- 虚函数、纯虚函数、虚继承、多继承
来源:http://www.tnove.com/?p=57 C++的一个特征是多太,其中多态主要表现在 1.编译时多态 函数overload实现 2.运行是多态 虚函数override实现 其中虚 ...
- 避免在派生类中重新定义基类的非虚函数
我们都知道,在基类中定义虚函数的目的是允许派生类拥有相同接口却可以有不同的实现,通过对象的指针或引用来访问虚函数可以实现运行时的多态.这么说来,在派生类中重定义(override)虚函数是没有任何问题 ...
- 在UE4中实现虚函数
对C++有些了解的同学都知道虚函数的实现方式如下 class A { public:virtual void Init(); };class B: public A { public:virtual ...
- override,final的使用,两者都是针对虚函数,也就是说要有virtual关键字
1.override,final的使用,两者都是针对虚函数,也就是说要有virtual关键字 #include <iostream> //C++中的final和override主要是 ...
- vs 不能自动 析构函数_深入理解C++虚函数的override、overload与hide以及虚析构函数...
今天主要讲的是虚函数的override与overload的区别.首先我们来看一段代码: 示例代码 #include <stdio.h> #include <string> #i ...
- 虚函数和纯虚函数--最通俗易懂的讲解
上帝是一个程序员,创造了动物(基类),给予了动物吃饭,睡觉,叫唤等通用功能.(封装) 只指定了平均睡觉八小时(虚函数),其中没有指定具体的吃饭,叫唤的行为.(纯虚函数) 然后细分一下,动物有猫狗羊和人 ...
- C++中的各种“虚“-- 虚函数、纯虚函数、虚继承、虚基类、虚析构、纯虚析构、抽象类讲解
C++中的各种"虚" 1. 菱形继承 1.1 虚继承 && 虚基类 1.2 虚基类指针(vbptr)&& 虚基类表(vbtable) 2. 多态 2 ...
最新文章
- 机器学习中的一些概念
- 微软开源: 老旧照片修复的AI算法
- linux ubuntu R 无法安装rggobi包的原因及解决方案
- 机器人编程语言python-5大机器人流行编程语言对比,你学会了哪种?
- NYOJ 158 省赛来了
- ARM裸机篇--按键中断
- Windows服务的程序方面的资料
- 学以致用,Python定时采集微博评论
- 江苏省消保委约谈14家企业,要求确保弹窗一键关闭无障碍实现
- 一块移动硬盘怎样兼容Mac和Windows系统,并且可以在time machine上使用
- 数学建模1---基本方法和步骤
- AdBlock广告拦截插件的实现原理
- 《编码:隐匿在计算机软硬件背后的语言》一书勘误
- 网站社交登录之微博登录
- Android短信拦截机制适配的坑(下)--4.4以上系统,主要是6.0
- 派克Parker耐高低温伺服电机在汽车检测行业中的重要应用
- js前端base64转码解码
- PHP 重启 php-fpm 的几种方法
- TMC5160 静音驱动器
- Invariance Matters: Exemplar Memory for Domain AdaptivePerson Re-identification