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. Selenium基本用法以及元素定位

    一.Selenium 简介 Selenium是ThroughtWorks公司一个强大的开源Web功能测试工具系列,提供一套测试函数,用于支持Web自动化测试.函数非常灵活,能够完成界面元素定位.窗口跳 ...

  2. JAVA数据类型能串门不?

    JAVA这几种数据类型,能否串门?入了人家门,就得按人家规矩来,入乡随俗哦,难免发生有自觉的 还有不情愿被动的. 自动类型转换 自动类型转换:容量小的数据类型可以自动转换为容量大的数据类型.在图中,黑 ...

  3. jQuery 属性操作 - addClass() 和 removeClass() 方法

    实例 向第一个 p 元素添加一个类: $("button").click(function(){ $("p:first").addClass("int ...

  4. MySQL学习之用户管理

    用户权限管理 用户权限管理:在不同的项目中给不同的角色(开发者)不同的操作权限,为了保证数据库数据的安全. 简单点说:有的用户可以访问并修改这个数据,而有些用户只能去查看数据,而不能修改数据.就如同博 ...

  5. MySQL 5.7增强半同步测试

            we've know the machenism of semi-synchronous replication in my previous article,let's do som ...

  6. 获取地图的信息到input里

    在最近项目中,我接触了百度地图的API写法,对其中的代码有了一点兴趣,所以我在完成任务后,在办公室里学习了百度地图的相关引用,并申请了服务秘钥: E7PCho0sv3FdzmjC901ttP0HrS9 ...

  7. 坑爹的jquery ui datepicker

    1.坑爹的jquery ui datepicker 竟然不支持选取时分秒,害的我Format半天 期间尝试了bootstrap的ditepicker,但是不起作用,发现被jquery ui 覆盖了, ...

  8. django-models 数据库取值

    django.shortcuts import render,HttpResponse from app01.models import * # Create your views here. def ...

  9. 实验1 查看CPU和内存,用机器指令和汇编指令编程

    ·实验任务 (1)使用Debug,用E命令和A命令以两种方式将指令写入内存 机器码        汇编指令 b8 20 4e    mov ax,4e20h 05 16 14    add ax,14 ...

  10. 推荐 的FPGA设计经验(1)组合逻辑优化

    主要内容摘自Quartus prime Recommended Design Practices For optimal performance, reliability, and faster ti ...