在C++中有两个很是容易混淆的概念,分别是函数重载(overload)和函数重写(overwirte)。虽然只相差一个字,可是它们二者之间的差异仍是很是巨大的。编程
而经过深刻了解这两个概念的区别,会对C++的面向对象机制有一个更深刻的理解。数组
当函数具备相同的名称,可是参数列表不相同的情形(包括参数的个数不一样或参数的类型不一样),这样的同名而不一样参数的函数之间,互相被称之为重载函数。ide
如下的集中写法,分别表示了哪些是重载的,哪些不是重载的。
(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)除返回值不一样外,均有参数类型或参数个数不一样的状况,所以构成重载关系。spa
读者可能会问,既然函数重载这个概念这么拗口,并且有时候又容易和函数重写概念弄混而致使出错,那么为何在C++里面要有这么一个概念出现呢?指针
缘由其实也很简单,就是由于在一个程序中,会出现不少不少,完成的函数功能彻底相同,而仅仅是函数的参数略有不一样的情形。这时若是没有函数重载这个概念,那么开发人员恐怕就要为如何为功能彻底相同的函数起不一样的名而头疼了。调试
在各类开源的库中,咱们也常常能够看到函数重载的身影。好比:对象
(1)类的构造函数,一般就是函数重载的典型应用。由于一个类一般是能够有不少种构造方式的。
如QT里面的QString类的构造函数,提供了9种不一样的构造函数,这9种构造函数的函数名彻底相同,可是它们的参数类型或参数个数却不彻底相同,所以是合法的。如图所示: blog
(2)类的成员函数,如赋值函数等。
如VTK的vtkImageData类的两个成员函数就是重载的。如: 继承
这两个成员函数的函数名称都是SetDimensions(),可是第一个函数的参数是3个int型的值;另外一个函数的参数是一个const int型的数组,返回值都是void。这样也是能够构成函数重载的。
在安装有编程助手的状况下编写代码时,若是遇到一个类的成员函数有重载时,助手一般会提示开发者,要选择哪个重载函数。以下图所示。vtkImageData的SetDimensions()函数有两个重载形式,所以在编写代码时,助手会提示2 of 2,表示这是2个重载函数中的第二个,点击能够切换到第一个重载函数。开发者须要根据上下文的要求,来选择相应的重载函数进行编写。
虽然与函数重载仅仅只有一个字的差异,可是这两个概念倒是相差了很远很远。它俩彷佛一点关系都没有。也正由于如此,这个很是考验C++语言的基本功,也是历年C++笔试中常常会出现的考题。
函数重写,也被称为覆盖,是指子类从新定义父类中有相同名称和参数的虚函数,主要在继承关系中出现。
有个规则是赋值兼容性原则,而这个规则有bug,当子类和父类的函数重名的时候,不论是基类的对象去指向/引用子类对象,都是调用基类的函数,而和子类无关,这明显是一个bug,
因此,只能用函数重写(也就是引出了多态),这样就能够区分和调用子类和父类里重名的函数了。[这里不能用函数重载是由于这里发生在两个类里,而重载不只仅是在一个类里进行区分]
今天在工做的时候,就是由于在重写基类的某一个虚函数时,因为在复制时把函数的参数类型和基类的参数类型搞得不一致了,致使重写失败。
所以,在调试代码时,本觉得程序会进入派生类的重写后的函数中,可是实际却一直进入基类的函数中。最后在网上查询缘由时,才恍然大悟,原来是因为本身的失误,而致使了重写失败。
具体是:
Dx3DActorRotationPanOplayer : public DxBaseOplayer.
在基类DxBaseOplayer中有一系列的关于响应鼠标事件的虚函数:
其中,在派生类中我想从新实现其中的一个虚函数 OnMouseLeave()。
可是,我在子类定义该函数时,却写成了:
表面上看起来彷佛很像。可是仔细一看,函数的参数是不相同的。
基类的第一个参数类型是:QEvent, 而派生类的第一个参数类型是:QMouseEvent。
正是因为这个参数类型的不一样,而致使了派生类实际并无重写基类的这个成员函数。
所以,在基类的指针调用这个函数时,便没法调用到子类的这个重写函数了。 只要把派生类的第一个参数类型也修改成QEvent,那么便实现了函数的重写了。