在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 object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14 // Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14 (surprise!)
pd->g(3.14f); // Derived::g(int) 3 // Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14 return ;
}

  在上面这个例子中:

  • 函数Derived::f(float)覆盖(override)了Base::f(float)。
  • 函数Derived::g(int)改写/隐藏(overwrite)了Base::g(float)。
  • 函数Derived::h(float)改写/隐藏(overwrite)了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 object
pb->f(3.14f); // Base::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14 return ;
}

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 behavior
d->g(); // Derived::g() vd->f(); // Base::f() Bad behavior
vd->g(); // VirtualDerived::g() delete d;
delete vd; return ;
}

 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,也就决不能这样做。

  不管采用上面的哪一种论据都可以得出这样的结论:任何条件下都要禁止重新定义继承而来的非虚函数。

C++中的Overload、Override和Overwrite的更多相关文章

  1. overload, override和overwrite之间的区别

    Overload.Overwrite和Override的概念比较容易混淆,而且Overwrite和Override的中文翻译五花八门,让人很Confuse,顾保持英文原意: Overload  重载 ...

  2. c++中的overload、overwrite、override

    作为初学者,本文只从语法和简单的使用角度对overload.overwrite.override进行了区分,不曾涉及原理,记录下来以供查阅. 1.verload(重载) 1.1 基本要求: c++中的 ...

  3. 方法的覆盖(override)、重载(overload)和重写(overwrite)

    body { background-color: white } .markdown-body { min-width: 200px; max-width: 760px; margin: 0 auto ...

  4. 大约 C++ 几个方面分析--overload, override, overwrite, rewrite

    overload, override, overwrite, rewrite 这几个单词常常出如今 C++ 书中,翻阅一些译版后发现并未对 override, overwrite, rewrite 严 ...

  5. Overload&Override

    Overload&Override overload-–重载 方法的重载就是在一个类中,可以定义多个有相同名字,但参数不同的方法.调用时,会根据不同的参数表选择对应的方法. 规    则:两同 ...

  6. 导入android项目在eclipse中会报@Override错误

    很多时候导入android项目在eclipse中会报@Override错误,这是由于java编译器的版本不正确,Java 1.5的编译器默认对父类的方法进行覆盖,采用@Override进行说明:但1. ...

  7. 浅析C#中new、override、virtual关键字的区别

    Virtual : virtual 关键字用于修饰方法.属性.索引器或事件声明,并使它们可以在派生类中被重写. 默认情况下,方法是非虚拟的.不能重写非虚方法. virtual 修饰符不能与 stati ...

  8. C#学习笔记(16)——C#中重写(override)和覆盖(new)的区别

    说明(2017-7-17 23:04:45): 原文: C#中重写(override)和覆盖(new)的区别 重写 用关键字 virtual 修饰的方法,叫虚方法.可以在子类中用override 声明 ...

  9. c#中abstract、override、new、virtual、sealed使用

    abstract     修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现 ...

随机推荐

  1. LeetCode Unique Paths (简单DP)

    题意: 给出一个m*n的矩阵,robot要从[1][1]走到[m][n],每次只能往下/右走,问有多少种走法? 思路: DP的经典问题.先将[1][1]设为1,然后两种走法就是分别用[i][j]去更新 ...

  2. c++11编码规范 NULL还是nullptr

    0和nullptr/NULL 至于指针(地址值),根据实际选择用0.NULL还是nullptr.对使用了C++11特性的项目,选用nullptr:对于C++03项目,推荐NULL,因为它像是一个指针

  3. 服务调用方案(Spring Http Invoker) - 我们到底能走多远系列(40)

    我们到底能走多远系列(40) 扯淡:  判断是否加可以效力于这家公司,一个很好的判断是,接触下这公司工作几年的员工,了解下生活工作状态,这就是你几年后的状态,如果满意就可以考虑加入了. 主题: 场景: ...

  4. 简单选择排序算法(C++版)

    #include <iostream> using namespace std; /** Simple Select Sort * brief: * Key: * * position: ...

  5. yii2后台上传图片,前台也能显示 的方法

    备注:::很low    高端人士 勿入  支持 吐槽  有你们的吐槽才有我的进步 还不会yii上传的  go   out    (哈哈,开玩笑)

  6. 137. Single Number II

    Given an array of integers, every element appears three times except for one. Find that single one. ...

  7. HDU 5944 暴力

    Fxx and string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)T ...

  8. ZOJ 1125 Floating Point Numbers

    原题链接 题目大意:给一个16位的数字,表示一个浮点数,按照规则转换成科学计数法表示. 解法:注释比较清楚了,注意浮点运算的四舍五入问题. 参考代码: #include<iostream> ...

  9. C++ Primer : 第十章 : 泛型算法 之 只读、写和排序算法

    大多数算法都定义在<algorithm>头文件里,而标准库还在头文件<numeric>里定义了一组数值泛型算法,比如accumulate. ●  find算法,算法接受一对迭代 ...

  10. HDU-1561 The more, The Better (树形DP+分组背包)

    题目大意:给出一片森林,总共有n个点,并且都有权值.从中选出m个,使权值和最大.其中,选某个节点之前必须先选其父节点. 题目分析:给所有的树都加一个共同的权值为0的根节点,使森林变成一棵树.定义状态d ...