代码编译运行环境:VS2017+Debug+Win32


1.函数重载(Function Overload)

1.1 定义

C++ 规定在同一作用域中,同名函数的形式参数(指参数的个数、类型或者顺序)不同时,构成函数重载。

1.2 用法

比如,要从两个变量中返回其中较大的一个值,可以编写如下两个构成重载的函数。

int max(int a,int b)
{return a>b?a:b;
};double max(double a,double b)
{return a>b?a:b;
}

1.3 注意事项

(1)函数返回值类型与构成函数重载无任何关系;
(2)类的静态成员函数与普通成员函数可以形成重载;
(3)函数重载发生在同一作用域,如类成员函数之间的重载、全局函数之间的重载。

2.函数隐藏(Function Hiding)

2.1 定义

函数隐藏指不同作用域中定义的同名函数构成函数隐藏(不要求函数返回值和函数参数类型相同)。比如派生类成员函数屏蔽与其同名的基类成员函数、类成员函数屏蔽全局外部函数。请注意,如果在派生类中存在与基类虚函数同返回值、同名且同形参的函数,则构成函数重写。

2.2 用法用例

请仔细研读以下代码。

#include <iostream>
using namespace std;void func(char* s)
{cout<<"global function with name:"<<s<<endl;
}class A
{void func() {cout<<"member function of A"<<endl;}
public:void useFunc() {//func("lvlv");//A::func()将外部函数func(char*)隐藏func();::func("lvlv");}virtual void print() {cout<<"A's print"<<endl;}
};class B:public A
{
public://隐藏A::vodi useFunc()void useFunc() {          cout<<"B's useFunc"<<endl;}//隐藏A::vodi useFunc()int useFunc(int i) {      cout<<"In B's useFunc(),i="<<i<<endl;return 0;} virtual int print(char* a) {cout<<"B's print:"<<a<<endl;return 1;}//下面编译不通过,因为对父类虚函数重写时,需要函数返回值类型,函数名称和参数类型全部相同才行// virtual int print() //{// cout<<"B's print:"<<a<<endl;//}
};int main()
{A a;a.useFunc();B b;b.useFunc();//A::useFunc()被B::useFunc()隐藏b.A::useFunc();b.useFunc(2);//b.print();//编译出错,A::print()被B::print(char* a)隐藏b.A::print();b.print("jf");
}

程序执行结果:

member function of A
global function with name:lvlv
B's useFunc
member function of A
global function with name:lvlv
In B's useFunc(),i=2
A's print
B's print:jf

2.3 注意事项

对比函数隐藏与函数重载的定义可知:
(1)派生类成员函数与基类成员函数同名但参数不同。此时基类成员函数将被隐藏(注意别与重载混淆,重载发生在同一个类中);
(2)函数重载发生在同一作用域,函数隐藏发生在不同作用域。

3.函数覆盖(Function Override)

网上和很多书籍多都会涉及函数覆盖与函数重写的概念,众说纷纭,加大了许多初学者的学习难度,甚至产生误导。事实上,函数覆盖指的就是函数重写。

3.1 定义

重定义派生类中与基类同返回类型、同名和同参数的虚函数,构成虚函数覆盖,也叫虚函数重写。关于返回类型存在一种特殊情况,即返回类型可以不用完全一致,协变返回类型(covariant return type)也可以构成虚函数重写。

3.2 虚函数重写与协变返回类型

如果虚函数返回指针或者引用时(不包括 value 语义),子类中重写的函数返回的指针或者引用是父类中被重写函数所返回指针或引用的子类型(这就是所谓的协变返回类型)[4]^{[4]}[4]。看示例代码:

#include <iostream>
using namespace std;class A{};
class B:public A{};class Base
{
public:virtual A& show() {cout<<"In Base"<<endl;return *(new A);}
};class Derived:public Base
{
public://返回值协变,构成虚函数重写B& show() {cout<<"In Derived"<<endl;return *(new B);}
};

3.3 注意事项

(1)函数覆盖就是虚函数重写,而不是函数被"覆盖"。
从上面的代码可以看出,函数是不可能被“覆盖”的。有些人可能会错误地认为函数覆盖会导致函数被"覆盖"而"消失",将不能被访问,事实上只要通过作用域运算符::就可以访问到被覆盖的函数。因此,不存在被”覆盖“的函数。

(2)函数覆盖是函数隐藏的特殊情况。
对比函数覆盖和函数隐藏的定义,不难发现函数覆盖其实是函数隐藏的特例。

如果派生类中定义了一个与基类虚函数同名但参数列表不同的非virtual函数,则此函数是一个普通成员函数(非虚函数),并形成对基类中同名虚函数的隐藏,而非虚函数覆盖(重写)。

《C++高级进阶教程》中认为函数的隐藏与覆盖是两个不同的概念。隐藏是一个静态概念,它代表了标识符之间的一种屏蔽现象,而覆盖则是为了实现动态联编,是一个动态概念。但隐藏和覆盖也有联系:形成覆盖的两个函数之间一定形成隐藏。例如,可以对虚函数采用“实调用”,即尽管被调用的是虚函数,但是被调用函数的地址还是在编译阶段静态确定的,那么派生类中的虚函数仍然形成对基类中虚函数的同名隐藏。

参考如下代码,考察虚函数的实调用和虚调用。

#include <iostream>
using namespace std;class Base
{
public:virtual void show() {cout<<"In Base"<<endl;}
};class Derived:public Base
{
public:void show() {cout<<"In Derived"<<endl;}
};int main()
{Base b;b.show();Derived d;d.show();          //对函数show()的实调用d.Base::show();    //对函数show()的实调用Base *pb=NULL;     pb=&d;             pb->show();        //对函数show()的虚调用pb->Base::show();  //对函数show()的实调用
}

程序运行结果:

In Base
In Derived
In Base
In Derived
In Base

4.总结

在讨论相关概念的区别时,抓住定义才能区别开来。C++ 中函数重载隐藏和覆盖的区别,并不难,难就难在没弄清定义,被网上各种说法弄的云里雾里而又没有自己的理解。

在这里,牢记以下几点,就可区分函数重载、函数隐藏、函数覆盖和函数重写的区别:
(1)函数重载发生在相同作用域;
(2)函数隐藏发生在不同作用域;
(3)函数覆盖就是函数重写。准确地叫作虚函数覆盖和虚函数重写,也是函数隐藏的特例。

关于三者的对比,李健老师在《编写高质量代码:改善C++程序的150个建议》一书中给出了较为详细的总结,如下表所示:

三者 作用域 有无virtual 函数名 形参列表 返回值类型
重载 相同 可有可无 相同 不同 可同可不同
隐藏 不同 可有可无 相同 可同可不同 可同可不同
重写 不同 相同 相同 相同(协变)

参考文献

[1] 陈刚.C++高级进阶教程[M].第一版.武汉:武汉大学出版社,2008.P110-112
[2] 百度百科.函数隐藏
[3] 李健.编写高质量代码:改善C++程序的150个建议.第一版.北京:机械工业出版社,2012.1:122-125
[4] C++基础:函数重写(override)与协变返回类型(covariant return type)

C++ 函数重载、隐藏与覆盖的区别相关推荐

  1. java隐藏类_java Class类中隐藏和覆盖的区别

    覆盖 子类扩展父类获得父类当中的方法和成员变量,可是父类中的某些方法,不适合子类本身,所以则需要重写,子类 定义父类方法的过程就是方法的覆盖,字段不能被覆盖,只能被隐藏 用static描述的属性和方法 ...

  2. 【转】c++重载、覆盖、隐藏——理不清的区别

    原文网址:http://blog.sina.com.cn/s/blog_492d601f0100jqqm.html 再次把林锐博士的<高质量c++编程指南>翻出来看的时候,再一次的觉得这是 ...

  3. java隐藏与覆盖_Java 隐藏和覆盖

    我们知道,在JAVA中,子类可以继承父类,如果子类声明的方法与父类有重名的情况怎么办,大伙儿都知道要是重写,但是实际上这又分为两种情况,就是方法和变量在继承时的覆盖和隐藏问题,这些概念性的东西看似无聊 ...

  4. C++成员函数重载、覆盖和隐藏的区别

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  5. 《C++成员函数重载、覆盖与隐藏》

    <成员函数的重载.覆盖与隐藏> ------------------------------------------------------------------------------ ...

  6. 函数重载和覆盖(重写)的区别

    1.重载:函数重载是指在同一作用域内(名字空间),可以有一组具有相同函数名,不同参数列表的函数: 2.覆盖(也叫重写):指在派生类中重新对基类中的虚函数(注意是虚函数)重新实现.即函数名和参数都一样, ...

  7. C++多态及重载(overload),覆盖(override),隐藏(hide)的区别

    转自 Hackbuteer1 http://blog.csdn.net/hackbuteer1/article/details/7475622 C++编程语言是一款应用广泛,支持多种程序设计的计算机编 ...

  8. C++父类与子类关系以及函数重载、覆盖和隐藏规则 http://blog.csdn.net/xingyu19871124/article/details/7640131

    http://blog.csdn.net/xingyu19871124/article/details/7640131 C++父类与子类关系以及函数重载.覆盖和隐藏规则 标签: c++class语言编 ...

  9. 深入理解成员函数的重载、隐藏、覆盖规则(二)

    本文作者:islwj 本文出处:http://blog.csdn.net/islwj 声明: 本文可以不经作者同意, 任意复制, 转载, 但任何对本文的引用都请保留文章开始前三行的作者, 出处以及声明 ...

最新文章

  1. 相似度算法(http://blog.sina.com.cn/s/blog_62b83291010127bf.html)
  2. What?你还搞不懂什么是物体检测?
  3. java mbean获取堆信息_实时取得虚拟机类信息、内存信息、MXBean的使用方法
  4. 10个基于 Ruby on Rails 构建的顶级站点
  5. 【企业级框架整合】Springmvc+mybatis+restful+bootstrap框架整合
  6. Linux编程基础之Makefile的使用
  7. 三角函数:加减法公式
  8. 高一计算机应用自我鉴定,高中生自我鉴定
  9. 今日头条2018校招测试开发方向(第一、二、三、四批)编程题汇总 - 题解
  10. matlab中a2qua,matlab-toolbox-forINS 惯性导航系统的 工具箱,里面包含使用说明以及各个m文件的功能 272万源代码下载- www.pudn.com...
  11. 针对学校出现猪流感而做的一个简单的小软件(更新版)
  12. 硬件-3-家庭联网常用设备
  13. Linux userdel 和 deluser 的区别
  14. python散点图图例显示标记点类型_python – matplotlib散点图中的标记点
  15. MacBook不接电源实现外接显示器功能
  16. 《富爸爸,穷爸爸》思维导图和学习笔记
  17. 隐藏进程占用cpu高
  18. URL如何转换成pdf?
  19. C# POST——爬取B站直播时的弹幕
  20. 高校教师工资管理系统java_基于jsp的高校职工工资管理系统-JavaEE实现高校职工工资管理系统 - java项目源码...

热门文章

  1. dockerfile实例
  2. Linux中zip和tar处理软链接的差异与选择
  3. iOS越狱开发theOS搭建
  4. redis简单运用,数据类型,适合入门
  5. linux 比较两个文件夹不同 (diff命令, md5列表)
  6. CSS工具之CSS重置(CSS Reset)
  7. Tomcat 配置数据库连接池
  8. Struts2学习(二):第一个Action
  9. Tomcat与Apache集成
  10. java 送参数_关于java:如何以编程方式发送带参数的HTTP请求?