重载(overload)是指函数不同的参数列表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。在同一可访问域内(注意同一访问域,基类和派生类不属于同一访问域)被声明的几个具有不同参数列表(参数类型、个数、顺序)的同名函数,程序会根据不同的参数列来确定具体调用哪个函数。对于重载函数的调用,在编译期间就已经确定,是静态的,它们的地址在编译期间就绑定好了,与多态无关。注意,重载不关心函数的返回值类型。
成员函数被重载的特征:
(1) 相同的范围(在同一个类中)
(2)函数名字相同
(3)参数不同
(4)virtual关键字可有可无
覆盖(override)是指派生类中存在重新定义基类的函数,其函数名/参数列/返回值类型必须同基类中对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体不同。当子类重新定义了父类的虚函数后,父类指针会进行动态绑定。
覆盖的特征如下:
(1)不同的范围(分别位于基类和派生类中)
(2)函数名、参数列、返回值严格一致
(3)基类函数必须有virtual关键字
隐藏(hide)是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类函数与基类函数同名但是参数不同,则无论有无virtual关键字,基类函数都将被隐藏
(2)如果派生类函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时基类的函数被隐藏
注:在不同域中,编译器只看函数名,不看其它东西
关于隐藏和重载有一个很好的例子:
class A{
public:
void f(int i){cout << "A" << endl;}
};
class B{
public:
void f(int i){cout << "B" << endl;}
};
class C : public A, public B{
public:
void f(char *s){cout << "C" << endl;}
};
int main(void)
{
C c;
c.f(2);//如果c++不进行覆盖的化,编译器没法确定调用的是A::f()还是B::f()。
//这不在同一个域中,所以跟重载没有半点关系。
return 0;
}
如果硬是希望在C中进行重载A的成员函数的化,可以这么设计:
class C : public A, public B {
public:
using A::f;
void f(char* s) {cout << "C" << endl;}
};
注:JAVA中就没有隐藏这种说法,举个例子
class CB {
public void f(){
System.out.println("CB::f()");
}
}
class CD extends CB {
public void f(int a){
System.out.println("CD::f(int)");
}
}
public class MyTest {
public static void main(String args[])
{
System.out.println("helloWorld");
CD test = new CD();
test.f();
test.f(1);
}
}
运行结果就是:
helloWorld
CB::f()
CD::f(int)
形象一点就是这个Java和C++就有区别了,感觉Java的比较合常理啊,我爸爸有辆大奔,我自己有辆宝马,我爸爸说,我的大奔就是你的大奔,那我当然既能开大奔,又能开宝马了,凭什么只能开宝马呢?
另外JAVA中private函数不能重载,比如:
class CB {
private void f(){
System.out.println("CB::f()");
}
public void ff(){
f();
}
}
class CD extends CB {
public void f(){
System.out.println("CD::f()");
}
}
public class MyTest {
public static void main(String args[])
{
System.out.println("helloWorld");
CD cd = new CD();
CB cb = new CB();
CB cbd = new CD();
cd.ff();
cb.ff();
cbd.ff();
}
}
运行结果:
helloWorld
CB::f()
CB::f()
CB::f()
而在c++中,直接重载了!
class CB {
private:
virtual void f(){
cout<< "CB::f()" << endl;
}
public:
void ff(){
f();
}
};
class CD : public CB {
private:
void f(){
cout<< "CD::f()" << endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
CD test;
CB test2;
CB * cb = &test2;
CD * cd = &test;
CB * cbd = &test;
cb->ff();
cd->ff();
cbd->ff();
return 0;
}
运行结果:
CB::f()
CD::f()
CD::f()
不过说实在的,我觉得没必要这么转牛角尖,为啥要覆盖私有成员函数呢?派生类应该根本见不到基类的私有成员接口,否则破坏了封装性