1. 前言:

  在C++中有两个非常容易混淆的概念,分别是函数重载(overload)和函数重写(overwirte)。虽然只相差一个字,但是它们两者之间的差别还是非常巨大的。

  而通过深入了解这两个概念的区别,会对C++的面向对象机制有一个更深入的理解。

2 函数重载(overload function)

2.1 函数重载的概念:

2.1.1 概念:

当函数具有相同的名称,但是参数列表不相同的情形(包括参数的个数不同或参数的类型不同),这样的同名而不同参数的函数之间,互相被称之为重载函数。

2.1.2 基本条件:

  • 函数名必须相同;
  • 函数参数必须不相同,可以是参数类型或者参数个数不同;
  • 函数返回值可以相同,也可以不相同。(备注:但是如果函数的名称和参数完全相同,仅仅是返回值类型不同,是无法进行函数重载的。

2.1.3 注意:

  • 只能通过不同的参数样式进行重载,例如:不同的参数类型,不同的参数个数,或者不同的参数顺序
  • 不能通过访问权限、返回类型、抛出的异常不同而进行重载;
  • 重载的函数应该在相同的作用域下。

2.1.4 函数重载实例判断:

以下的集中写法,分别表示了哪些是重载的,哪些不是重载的。 
(1) void func1( int arg1); 
(2) void func1( double arg1); 
(3) void func1( int arg1, int arg2); 
(4) bool func1(int arg1, double arg2) 
(5) int func1(int arg1);

在上述的5个函数中,函数名称都是func1,完全相同;但是: 
(2)与(1)的参数个数相同,参数类型不同,构成重载; 
(3)与(1)和(2)的参数个数不同,构成重载; 
(4)与(1)和(2)的参数个数不同,与(3)的参数个数相同,但是第二个参数类型不同,构成重载; 
(5)与(1)的参数个数和参数类型均相同,仅返回值的类型不相同,不构成重载;但是(5)与(2),(3)和(4)除返回值不同外,均有参数类型或参数个数不同的情况,因此构成重载关系。

2.2 函数重载的应用

读者可能会问,既然函数重载这个概念这么拗口,而且有时候又容易和函数重写概念弄混而导致出错,那么为什么在C++里面要有这么一个概念出现呢?

原因其实也很简单,就是因为在一个程序中,会出现很多很多,完成的函数功能完全相同,而仅仅是函数的参数略有不同的情形。这时如果没有函数重载这个概念,那么开发人员恐怕就要为如何为功能完全相同的函数起不同的名而头疼了。

在各种开源的库中,我们也经常可以看到函数重载的身影。比如:

(1)类的构造函数,通常就是函数重载的典型应用。因为一个类通常是可以有很多种构造方式的。 
如QT里面的QString类的构造函数,提供了9种不同的构造函数,这9种构造函数的函数名完全相同,但是它们的参数类型或参数个数却不完全相同,因此是合法的。如图所示:

(2)类的成员函数,如赋值函数等。 
如VTK的vtkImageData类的两个成员函数就是重载的。如:

这两个成员函数的函数名称都是SetDimensions(),但是第一个函数的参数是3个int型的值;另一个函数的参数是一个const int型的数组,返回值都是void。这样也是可以构成函数重载的。

在安装有编程助手的情况下编写代码时,如果遇到一个类的成员函数有重载时,助手通常会提示开发者,要选择哪一个重载函数。如下图所示。vtkImageData的SetDimensions()函数有两个重载形式,因此在编写代码时,助手会提示2 of 2,表示这是2个重载函数中的第二个,点击可以切换到第一个重载函数。开发者需要根据上下文的要求,来选择相应的重载函数进行编写。


3 函数重写(override function)

虽然与函数重载仅仅只有一个字的差别,但是这两个概念却是相差了很远很远。它俩似乎一点关系都没有。也正因为如此,这个非常考验C++语言的基本功,也是历年C++笔试中经常会出现的考题。

3.1 函数重写(override function)

3.1.1 概念:

函数重写,也被称为覆盖,是指子类重新定义父类中有相同名称和参数的虚函数,主要在继承关系中出现。

3.1.2 基本条件:

  • 重写的函数和被重写的函数必须都为virtual函数,并分别位于基类和派生类中;
  • 重写的函数和被重写的函数,函数名和函数参数必须完全一致
  • 重写的函数和被重写的函数,返回值相同,或者返回指针或引用,并且派生类虚函数返回的指针或引用的类型是基类中被替换的虚函数返回的指针或引用的类型或者其子类型(派生类型)。

3.2 函数重写的应用

有个规则是赋值兼容性原则,而这个规则有bug,当子类和父类的函数重名的时候,不管是基类的对象去指向/引用子类对象,都是调用基类的函数,而和子类无关,这明显是一个bug,

所以,只能用函数重写(也就是引出了多态),这样就可以区分和调用子类和父类里重名的函数了。[这里不能用函数重载是因为这里发生在两个类里,而重载不仅仅是在一个类里进行区分]

 PS: 重写/多态是类的特性,而重载不是,在全局函数里也可以用重载
 

今天在工作的时候,就是因为在重写基类的某一个虚函数时,由于在复制时把函数的参数类型和基类的参数类型搞得不一致了,导致重写失败。

因此,在调试代码时,本以为程序会进入派生类的重写后的函数中,但是实际却一直进入基类的函数中。最后在网上查询原因时,才恍然大悟,原来是由于自己的失误,而导致了重写失败。

具体是: 
Dx3DActorRotationPanOplayer : public DxBaseOplayer. 
在基类DxBaseOplayer中有一系列的关于响应鼠标事件的虚函数:

其中,在派生类中我想重新实现其中的一个虚函数 OnMouseLeave()。 
但是,我在子类定义该函数时,却写成了:

表面上看起来似乎很像。但是仔细一看,函数的参数是不相同的。

基类的第一个参数类型是:QEvent, 而派生类的第一个参数类型是:QMouseEvent。

正是由于这个参数类型的不同,而导致了派生类实际并没有重写基类的这个成员函数

因此,在基类的指针调用这个函数时,便无法调用到子类的这个重写函数了。 
只要把派生类的第一个参数类型也修改为QEvent,那么便实现了函数的重写了。

函数重载(overload)和函数重写(override)的更多相关文章

  1. 重载(overload),覆盖/重写(override),隐藏(hide)

    写正题之前,先给出几个关键字的中英文对照,重载(overload),覆盖/重写(override),隐藏(hide).在早期的C++书籍中,常常把重载(overload)和覆盖(override)搞错 ...

  2. C# 方法重载 overload、方法重写 override、隐藏 new

    一.重载:同一个作用域内发生(比如一个类里面),定义一系列同名方法,但是方法的参数列表不同.这样才能通过传递不同的参数来决定到底调用哪一个. 值得注意的是,方法重载只有通过参数不同来判断调用哪个方法, ...

  3. c++中的重载(Overload)、覆盖(重写,Override) 、隐藏与using声明

    这些概念有时记住了,但可能没多久就忘了,还是记下来吧.网上找的一篇不错:这里  1 重载与覆盖 成员函数被重载的特征: (1)相同的范围(在同一个类中,不包括继承来的): (2)函数名字相同: (3) ...

  4. C++函数重载遇到了函数默认参数情况

    一.C++中的函数重载 什么是函数重载? 我的理解是: (1)用一个函数名定义不同的函数: (2)函数名和不同参数搭配时函数会有不同的含义: 举例说明: #include <stdio.h> ...

  5. C++的函数重载和main函数之外的工作

    今天被问到一个C++的函数重载问题,一下子没反应过来,这种基础的问题竟然忘记了,以下记录一下这些忘记的内容.     函数重载 函数重载的定义是:在相同的作用域中,如果函数具有相同名字而仅仅是形参表不 ...

  6. 方法重载overload与方法重写overwrite

    方法重载overload: 在同一个类中,出现相同的方法名,与返回值无关,参数列表不同:1参数的个数不同 2参数类型不同 在调用方法时,java虚拟机会通过参数列表来区分不同同名的方法 方法重写ove ...

  7. 【C++】多态性(函数重载与虚函数)

    多态性就是同一符号或名字在不同情况下具有不同解释的现象.多态性有两种表现形式: 编译时多态性:同一对象收到相同的消息却产生不同的函数调用,一般通过函数重载来实现,在编译时就实现了绑定,属于静态绑定. ...

  8. java中的重载(overload)和重写(override)区别

    方法重载(overload): 方法重载就是在一个类中可以创建多个方法,它们具有相同的名字,但是具有不同的参数和不同定义,调用方法时通过传递给他们的不同参数个数和参数列表决定具体使用     哪   ...

  9. 函数重载(overload)

    重载的定义及特点 在同一个类中,允许存在一个以上的同名函数, 只要他们的参数个数或者参数类型不同(不仅指两个重载方法的参数类型不同,还指相同参数拥有不同的参数类型顺序)就构成重载. 重载只和参数列表有 ...

随机推荐

  1. ORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listener

    执行$ORACLE_HOME/bin/dbstart 启动数据库提示如下: [oracle@prim bin]$ ./dbstart ORACLE_HOME_LISTNER is not SET, u ...

  2. oracle使用DBMS_RANDOM包生成随机数据

    (一)DBMS_RANDOM包信息 DBMS_RANDOM包包含3个存储过程,4个函数,1个类型,一共8个模块,如下. SQL> desc dbms_random Element Type -- ...

  3. Swift_ScrollView _ API详解

    Swift_ScrollView _ API详解 GitHub class ViewController: UIViewController,UIScrollViewDelegate { var sc ...

  4. java servlet数据库查询并将数据显示到jsp页面

    需要的jar包:mysql-connector-java.jar build path只是个jar包的引用,部署的时候想不丢包最好还是手动拷贝到对应项目的lib文件下. 在try{}中定义的变量为局部 ...

  5. 【解决】could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network

    在同一套环境中跑了很多个项目都是用 docker-compose的方式启动的,导致创建的自定义网络过多出现下面的报错 Error response from daemon: could not fin ...

  6. [转]关于sdk更新Android SDK Tools 25.3.1版本后使用sdk manager闪退

    昨天这两个manager还工作正常,今天更新了一下,发现不可用了,运行avd manager和sdk manager没反应,搜了好多文章,然后看到了下这篇文章<关于sdk更新Android SD ...

  7. python3 练习题100例 (三)

    题目三:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少? #!/usr/bin/env python3 # -*- coding: utf-8 -*- &qu ...

  8. Qt——事件

    1.常见事件 [1]鼠标事件 (1)坐标 x(),y(), 相对windows globalX() globalY() (2)获得点击 button() [2]键盘事件 [3]定时器事件 timerI ...

  9. C语言实验报告(五) 用自定义函数求2~n之间的素数

    #include<stdio.h>#include <math.h>int main(){  int i,n;  printf("input n:");  ...

  10. 长沙Uber优步司机奖励政策(1月11日~1月17日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...