一、基本概念
对于C++中经常出现的函数名称相同但是参数列表或者返回值不同的函数,主要存在三种情况:
1.函数重写(override)
函数重载主要实现了父类与子类之间的多态性,子类中定义与父类中名称和参数以及返回值都相同的虚函数。
1)重写的函数不能是static函数,必须是virtual函数,即函数在原始的基类中被声明为虚函数;
2)重写函数与基类函数分在两个类的声明和定义中,这也就导致二者的作用域不同;
3)重写函数的名称、参数列表以及返回值(即函数原型)都要与基类的函数相同;
4)重写函数的访问修饰符可以不同,尽管virtual函数是private的,在派生类中重写的函数可以是public或protect的
2.函数重载(overload)
指函数名称相同但是参数类型或者参数顺序不同的相同作用域中的函数,函数重载不能靠返回值来进行区分;
3.重定义(redefine)
指子类重新定义父类中的非虚函数(参数列表可以不同),这样父类中的对应函数将被隐藏。
二、重写(override)与重载(overload)的区别
1、函数重写是子类和父类之间的继承关系,是垂直关系;方法的重载是同一个类中方法之间的关系,是水平关系;
2、重写需要子类和父类中的两个函数的函数原型完全相同;重载要求两个函数参数列表不同;
3、在重写关系中,调用具体调用哪一个函数是根据(对象对应存储空间的实际类型)为准的,这涉及到动态绑定和静态绑定的问题,也就是虚函数的调用机制,而函数重载主要是靠形参列表的不同来区分具体调用哪个函数的。
#include <iostream> using namespace std; class BasicClass{ private: int a; public: //构造函数重载 BasicClass(){ a=0; }; BasicClass(int i):a(i){ }; BasicClass(const BasicClass &b):a(b.a){}; //基类的析构函数需要声明为虚函数 virtual ~BasicClass(){}; //函数重载实例 void overloadFunc(int k){ cout<<"overloadFunc single parameter:"<<k<<endl; }; void overloadFunc(int k,int t){ cout<<"overloadFunc two parameters:"<<endl; cout<<"k:"<<k<<endl; cout<<"t:"<<t<<endl; }; virtual void overrideFunc(){ cout<<"overrideFunc From Basic class!"<<endl; } }; class DeriveClass : public BasicClass{ private: public: //子类构造函数需要考虑到具体的基类成员初始化 //但是初始化的具体实现要交给相应类的构造函数来实现 DeriveClass(){}; DeriveClass(int t):BasicClass(t){}; ~DeriveClass(){}; //重定义隐藏 void overloadFunc(int k){ cout<<"redefine overloadFunc from derived Class!"<<endl; }; //重写 void overrideFunc(){ cout<<"overrideFunc From Derived Class!"<<endl; }; }; int main(){ BasicClass b; DeriveClass d; //重载 b.overloadFunc(1); b.overloadFunc(1,2); //重写 d.overrideFunc(); b.overrideFunc(); //隐藏 b.overloadFunc(1); d.overloadFunc(1); return 0; }
程序输出:
四、虚函数调用机制
陈皓的C++虚函数表解析:http://blog.csdn.net/haoel/article/details/1948051/
C++中每一个对每一个类对象都维护一个虚函数表,里面记录了对应的函数入口指针,按照C++ Primer上所说,虚函数是实现多太的最核心部分,通过指针或者引用以及虚函数的动态绑定就可以方便的实现多态了,在以上程序中主函数中加入如下代码
//通过指针和引用实现动态绑定 cout<<"*********************动态绑定********************"<<endl; BasicClass *pb=&d; pb->overrideFunc(); pb->overloadFunc(1); BasicClass &QuoteB=d; QuoteB.overrideFunc(); QuoteB.overloadFunc(1); cout<<"*********************静态绑定********************"<<endl; BasicClass b1=d; b1.overrideFunc(); b1.overloadFunc(1);
最终输出结果如下:
分析结果可一看出,动态绑定是运行时才决定调用哪个函数,通过指针过引用指向子类class对象从而实现多态,因此前两个overrideFunc输出是子类的结果;
但是父类对象直接被子类对象执行赋值操作,回导致隐式类型转换,将子类对象的基类部分复制给父类对象,并调用了父类对象的copy构造函数或者复制函数。