1. 重载(overload)
定义
- 在一个类内,如果存在若干个同名函数,而且这些函数之间可以用形参个数或形参类型区分开来的时候(注意不能靠函数返回类型区分),这几个函数就互为重载函数
注意点
重载发生在类内,不会发生在基类和派生类之间
函数名必须相同,形参个数或类型可以不同
重载函数之间必须依靠形参个数或形参类型来进行区分,不能依靠返回类型。
- 如果两个函数同名同参,但返回类型不同,编译器会因为二义性而报错
重载调用:通过类对象调用重载函数时,编译器通过传递的实参个数或类型去匹配相应的函数,而不会发生歧义。
- 体现了重载的作用:可以使用若干个同名函数
虚函数和普通函数之间也可以重载
2. 重写(override,覆盖)
定义
- 重写也称为覆盖,重写了一个方法以实现不同功能。一般用于子类继承父类时,重写父类中的方法。函数特征相同,具体实现不同。
注意点
重写只能出现在基类和派生类之间,当
- [1] 基类和派生类之间存在同名函数
- [2] 返回类型、形参个数和类型完全相同
- [3] 基类中的该函数必须是virtual(派生类中virtual可有可无)
则派生类中的该函数覆盖掉基类中的该函数,此性质用来实现多态
重写函数的访问修饰符可以不同,即使virtual是private的,派生类中改为public或protected也可以
3. 重定义(redefining,隐藏)
定义
- 重定义也称为隐藏,派生类对基类成员函数重新定义,即派生类定义了某个函数,该函数与基类中函数同名
注意点
重定义也只能出现在基类和派生类之间,当
- [1] 基类和派生类之间存在同名函数
- [2] 无论返回类型、形参个数和类型是否相同
则基类中的同名函数都会被隐藏
- 如果基类中该函数被重载,则重载函数都会被隐藏,包括虚函数
如果返回类型、形参个数和类型均相同,且基类中为virtual函数,则属于重写
如果要访问基类的该函数,需要在函数名前加上作用域操作符
4. 多态(polymorphism)
定义
多态是面向对象思想的精髓所在,使用多态是为了避免在父类中大量重载而引起代码臃肿和难于维护
关于多态,一种不严谨的说法是:继承是子类使用父类的方法,多态是父类使用子类的方法。
多态的分类
多态可以分为两类:静态多态性 + 动态多态性
[1] 静态多态性:又称编译时的多态性,静态多态性是通过函数的重载实现的
- 函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时就能决定调用哪个函数
[2] 动态多态性:又称运行时的多态性,动态多态性是通过虚函数实现的。
- 程序运行过程中才动态地确定操作所针对的对象
注意点
虚函数存在的唯一目的就是为了实现多态,成员函数要以多态的形式来执行,那么必须满足
- (1) 基类中这些成员函数为虚函数,并必须实现
- (2) 派生类中这些成员函数必须被重写(同名 + 同返回同形参个数和类型 + 基类中为virtual)
- (3) 将派生类的对象赋给基类的指针变量或引用,可用基类的指针或引用调用派生类的方法
实现多态,上述三个条件必须完全满足,虚函数的特性才能完全发挥出来,也才能实现多态。
不是多态的例子
[1] 派生类和基类都是虚函数,派生类中与基类函数同名,形参个数或类型与基类中不同,这种情况属于隐藏,不会报错
- 如果形参的个数和类型相同,返回类型也必须相同,否则编译会报错,因为返回类型发生了冲突,隐藏发生错误
[2] 基类中是虚函数,派生类中不是虚函数,派生类中与基类函数同名,返回类型或形参个数或类型与基类不同,这种情况也属于隐藏,如果返回类型、形参个数和类型均相同,这种情况属于重写,不会报错
[3] 基类中不是虚函数,派生类中是虚函数,或基类派生类中均不是虚函数,派生类中与基类函数同名,这种情况属于隐藏,同样也不会报错
附:实例说明
- [1] 重载,重写,重定义
#include <iostream>
using namespace std;
class BasicClass
{
private:
int a;
public:
//函数重载实例
void overloadFunc(int k)
{
cout<<"overloadFunc single parameter:"<<k<<endl;
}
void overloadFunc(int k,int t)
{
cout<<"overloadFunc two parameters:"<<" k:"<<k<<" t:"<<t<<endl;
}
virtual void overrideFunc()
{
cout<<"override fun from basic class!"<<endl;
}
};
class DeriveClass : public BasicClass
{
private:
public:
//重定义:隐藏
void overloadFunc(int k)
{
cout<<"redefine overloadFunc from derived Class!"<<endl;
}
//重写
void overrideFunc()
{
cout<<"override from derived class!"<<endl;
}
};
int main()
{
BasicClass a;
DeriveClass b;
//重载调用
cout<<"重载调用"<<endl;
a.overloadFunc(1);
a.overloadFunc(1,2); //根据形参来区分调用哪个函数
//重写
cout<<endl;
cout<<"重写-该性质可实现多态"<<endl;
b.overrideFunc();
a.overrideFunc();
//隐藏
cout<<endl;
cout<<"重定义/隐藏"<<endl;
a.overloadFunc(1);
b.BasicClass::overloadFunc(1); //重定义时可以通过作用域操作符访问基类函数
b.overloadFunc(1);
return 0;
}
- [2] 多态
#include <iostream>
using namespace std;
class A
{
public:
virtual void test(int a)
{
cout<<"basic class A: "<<a<<endl;
}
};
class B: public A
{
public:
void test(int b) //重写-覆盖
{
cout<<"derived class B: "<<b<<endl;
}
};
class C: public A
{
public:
void test(int c)
{
cout<<"derived class C: "<<c<<endl;
}
};
int main()
{
A *a0; //指针
B b;
C c;
A &a1 = b; //引用
A &a2 = c;
a0 = &b;
a0->test(2); //调用类B的test函数
a0 = &c;
a0->test(3); //调用类C的test函数
a1.test(4); //调用类B的test函数
a2.test(5); //调用类C的test函数
return 0;
}
Acknowledgements:
http://www.cnblogs.com/DannyShi/p/4593735.html
http://www.cnblogs.com/liangning/p/3968151.html
http://blog.csdn.net/loverooney/article/details/38307523
2017.09.26