C++中的Overload、Override和Overwrite
在C++语言中有一组基础的概念一直都容易混淆:Overload、Override和Overwrite分别表示什么意思?下面把这三个概念整理一下:
1. Overload(重载)
重载的概念最好理解,在同一个类声明范围中,定义了多个名称完全相同、参数(类型或者个数)不相同的函数,就称之为Overload(重载)。重载的特征如下:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
2. Override(覆盖)
覆盖的概念其实是用来实现C++多态性的,即子类重新改写父类声明为virtual的函数。Override(覆盖)的特征如下:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数列表完全相同;
(4)基类函数必须有virtual 关键字。
3. Overwrite(改写)
改写是指派生类的函数屏蔽(或者称之为“隐藏”)了与其同名的基类函数。正是这个C++的隐藏规则使得问题的复杂性陡然增加,这里面分为两种情况讨论:
(1)如果派生类的函数与基类的函数同名,但是参数不同。那么此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。那么此时,基类的函数被隐藏(注意别与覆盖混淆)。
借鉴一个网上的例子来看Overwrite(改写)的情况:
#include <iostream> using namespace std;class Base { public:virtual void f(float x){ cout << "Base::f(float) " << x << endl; }virtual void g(float x){ cout << "Base::g(float) " << x << endl; }void h(float x){ cout << "Base::h(float) " << x << endl; } };class Derived : public Base { public:virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }virtual void g(int x){ cout << "Derived::g(int) " << x << endl; }void h(float x){ cout << "Derived::h(float) " << x << endl; } };int main() {Derived d;Base *pb = &d;Derived *pd = &d;// Good : behavior depends solely on type of the objectpb->f(3.14f); // Derived::f(float) 3.14pd->f(3.14f); // Derived::f(float) 3.14// Bad : behavior depends on type of the pointerpb->g(3.14f); // Base::g(float) 3.14 (surprise!)pd->g(3.14f); // Derived::g(int) 3// Bad : behavior depends on type of the pointerpb->h(3.14f); // Base::h(float) 3.14 (surprise!)pd->h(3.14f); // Derived::h(float) 3.14return 0; }
View Code
在上面这个例子中:
- 函数Derived::f(float)重写了Base::f(float)。
- 函数Derived::g(int)隐藏了Base::g(float)。
- 函数Derived::h(float)隐藏了Base::h(float)。
4. 特殊情况说明
除了上面讲到的三种情况之外,还有一些比较容易迷惑的地方,例如:
4.1 同名的普通函数与const函数本质上是两个不同的函数,应该等价理解为这两个同名函数的参数是不同的。在派生类中的virtual函数理解上可能会有误解。
参见如下例子:
#include <iostream> using namespace std;class Base { public:virtual void f(float x){ cout << "Base::f(float) " << x << endl; } };class Derived : public Base { public:virtual void f(float x) const { cout << "Derived::f(float) " << x << endl; } };int main() {Derived d;Base *pb = &d;Derived *pd = &d;// Bad : behavior depends solely on type of the objectpb->f(3.14f); // Base::f(float) 3.14pd->f(3.14f); // Derived::f(float) 3.14return 0; }
View Code
4.2 基类中定义的virtual虚函数,在继承子类中同名函数自动都属于虚函数,可以不需要virtual关键字。
4.3 如果基类中定义的函数不是virtual,而子类中又将相同函数定义为virtual,则称之为越位,函数行为依赖于指针/引用的类型,而不是实际对象的类型。
参见如下例子:
#include<iostream> using namespace std;class Base { public:void f(){ cout << "Base::f() " << endl; }virtual void g(){ cout << "Base::g() " << endl; } };class Derived : public Base { public:virtual void f(){ cout << "Derived::f() " << endl; }void g(){ cout << "Derived::g() " << endl; } };class VirtualDerived : virtual public Base { public:void f(){ cout << "VirtualDerived::f() " << endl; }void g(){ cout << "VirtualDerived::g() " << endl; } };int main() {Base *d = new Derived;Base *vd = new VirtualDerived;d->f(); // Base::f() Bad behaviord->g(); // Derived::g() vd->f(); // Base::f() Bad behaviorvd->g(); // VirtualDerived::g() delete d;delete vd;return 0; }
View Code
5. 针对非虚函数的继承说明
在《Effective C++》中讲述了这样一个规则:任何条件下都要禁止重新定义继承而来的非虚函数。
公有继承的含义是 "是一个"(is a),"在一个类中声明一个非虚函数实际上为这个类建立了一种特殊性上的不变性"。如果将这些分析套用到类B、类D和非虚成员函数B::mf,那么:
(1)适用于B对象的一切也适用于D对象,因为每个D的对象“是一个”B的对象。
(2)B的子类必须同时继承mf的接口和实现,因为mf在B中是非虚函数。
那么,如果D重新定义了mf,设计中就会产生矛盾。如果D真的需要实现和B不同的mf,而且每个B的对象(无论怎么特殊)也真的要使用B实现的mf,那么每个D将不 "是一个" B。这种情况下,D不能从B公有继承。相反,如果D真的必须从B公有继承,而且D真的需要和B不同的mf的实现,那么,mf就没有为B反映出特殊性上的不变性。这种情况下,mf应该是虚函数。最后,如果每个D真的 "是一个" B,并且如果mf真的为B建立了特殊性上的不变性,那么,D实际上就不需要重新定义mf,也就决不能这样做。
不管采用上面的哪一种论据都可以得出这样的结论:任何条件下都要禁止重新定义继承而来的非虚函数。
转载于:https://www.cnblogs.com/kuliuheng/p/4107012.html
C++中的Overload、Override和Overwrite相关推荐
- overwrite java_java中的重写override或overwrite
java中的重写override或overwrite TestOverWrite.java ? class="java">class Person { private Str ...
- java中如何理解overload , override 和 overwrite
很多人总是容易把这三个词搞混淆,有的人甚至认为三者之间没多大区别.其实区别还是很大的,而且彻底搞清楚这三者间的关系还是很重要的,对于理解类与类之间的关系.类与接口.类内部方法与方法间的关系以及理解ja ...
- C++中overload,override,overwrite的区别?
C++中overload,override,overwrite的区别? Overload(重载) Override(覆盖) Overwrite(重写) Overload(重载) 在C++程序中,可以将 ...
- Override,OverWrite和Overload的区别和含义
今天在大话模式讨论中,提出了Override和OverWrite,对此有点模糊,进行一个小小的总结 1.OverLoad (重载) 在C#中,构造函数中用同一个函数标识,但是参数不同(包括类型和顺序) ...
- Override? Or Overwrite?
Override? Or Overwrite? java中有两个概念很容易搞混Override和Overwrite 1,Override 基本英文意思是: vt. 制服, 践踏, 奔越过, 蹂躏, 不 ...
- C#中new和override的区别
using System; //C#中new和override的区别 namespace Text {//在C#中,override和new都会覆盖父类中的方法.那它们两者之前有什么区别呢?//ove ...
- c++ overload 、override、overwrite
Overload.Overwrite和Override的概念比较容易混淆,而且Overwrite和Override的中文翻译五花八门,让人很Confuse,顾保持英文原意: Overload 重载 ...
- C++重载(overload)、重写(overwrite,也称隐藏)、覆盖(override)
一.重载(overload) 函数名相同,但是它的参数列表中参数的个数.类型或顺序不同.不能靠返回类型来判断.这个最简单,name mangling. (1)函数重载只会发生在同一个作用域中: (2) ...
- Java中,overload与override的区别
Java的overload(重载)与override(重写,覆盖)的区别 一,overload(重载) 1,overload(重载)表示同一个类中可以有多个名称相同的方法,但是这些方法的参数列表各不相 ...
最新文章
- JSPDF运用实例(解决图片跨域问题)
- 一个虐你千百遍的问题:“RPC好,还是RESTful好?”
- 阿里云消息队列python_41. Python Queue 多进程的消息队列 PIPE
- MyBatis-学习笔记09【09.Mybatis的多表操作】
- 一块电路板从“出生”到“成年”
- ASP.NET AJAX入门系列(10):Timer控件简单使用
- 浅谈对称加密与非对称加密
- ubuntu14.04+ceres安裝(亲测)
- 其他电子计算机配套产品及耗,F-商品和服务税收分类编码-.xls
- android 8.1.0编译以及卡刷包制作教程
- 九宫格日记 2017年12月19日(周二)
- 怎么用视频做gif动图?手把手教你制作gif表情包
- 第一章 SpringMvc---Web MVC简介
- IDEA插件-XTools
- 教你如何使用关键词获取淘宝和天猫的商品信息
- uni-app--》什么是uniapp?如何开发uniapp?
- linux光盘无刻录文件,Ubuntu Linux 中也能轻松刻录光盘
- 一、SpringCloud入门
- Stack Overflow是如何做应用缓存的
- 2021年熔化焊接与热切割考试资料及熔化焊接与热切割复审考试
热门文章
- cf519D . A and B and Interesting Substrings 数据结构map
- delphi构造析构调用顺序
- C#只能靠参数而不能靠返回值类型的不同来区分方法重载
- IKVM.NET_第一篇_概述
- [轉]最流行的PHP MVC框架
- route debugger
- Eigen问题解决:eigen_assert_exception’ is not a member of ‘Eigen’
- python字典最大长度_支持key过期失效和限制字典大小的开源项目 [python expire max length]...
- python显示当前日期_python显示当前时间
- 广义矩估计的一般步骤_【基本无害】动态理性预期理论与广义矩估计02