在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. Howto add permanent static routes in Ubuntu

    Static routing is the term used to refer to the manual method used to set up routing. An administrat ...

  2. LeetCode Bulls and Cows (简单题)

    题意: 给出两个数字,输出(1)有多少位是相同的(2)有多少位不在正确的位置上. 思路: 扫一遍,统计相同的,并且将两串中不同的数的出现次数分别统计起来,取小者之和就是第2个答案了. class So ...

  3. USB 描述符

    标准的USB设备有5种USB描述符:设备描述符,配置描述符,字符串描述符,接口描述符,端点描述符. // Standard Device Descriptor typedef struct { u8 ...

  4. python 的一些小技巧

    赋值: a, b, c = 'xixi', 'haha', 'hehe' 连接字典: >>> s = {1:'a', 2:'b', 3:'c'} >>> s.key ...

  5. Log4J 使用实战

    前言: 日志在开发和服务中扮演重要的角色, 有人用来追查/分析问题, 有人通过日志, 来记录重要的信息. 日志是数据分析和统计最重要的数据来源. 在Java领域, Log4j日志框架成为java开发人 ...

  6. leetcode 141. Linked List Cycle ----- java

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...

  7. DDL、DML、

     SQL语言的分类 SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL. 1. 数据查询语言DQL数据查询语言DQL基本结构是由SELECT子句,F ...

  8. 利用Web服务器网络打洞

    好了有些标题党了.这里想说的是:某些网络,除了http 80服务,其它端口的服务都被限制了,这个时候可以用http web服务器来进行代理转发. 以Apache为例,支持ssh登录到其它服务器的配置如 ...

  9. java的nio之:java的bio流下实现的socket服务器同步阻塞模型和socket的伪异步的socket服务器的通信模型

    同步I/O模型的弊端===>每一个线程的创建都会消耗服务端内存,当大量请求进来,会耗尽内存,导致服务宕机 伪异步I/O的弊端分析===>当对Socket的输入流进行读取操作的时候,它会一直 ...

  10. 论文笔记之: Bilinear CNN Models for Fine-grained Visual Recognition

    Bilinear CNN Models for Fine-grained Visual Recognition CVPR 2015 本文提出了一种双线性模型( bilinear models),一种识 ...