1. 程式人生 > >C++中成員函式的過載、覆蓋與隱藏

C++中成員函式的過載、覆蓋與隱藏

成員函式被過載的特徵:

(1)相同的範圍(在同一個類中);
(2)函式名字相同;
(3)引數不同;
(4)virtual關鍵字可有可無。

覆蓋是指派生類函式覆蓋基類函式,特徵是:

(1)不同的範圍(分別位於派生類與基類);
(2)函式名字相同;
(3)引數相同;
(4)基類函式必須有virtual關鍵字。

隱藏是指派生類的函式遮蔽了與其同名的基類函式,規則如下:

(1)如果派生類的函式與基類的函式同名,但是引數不同。此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。
(2)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)。

例:

#include <iostream.h>
class Base
{
public:
     virtual	void  f(float x){ cout << "Base::f(float) " << x << endl; }
     void g(float x){ cout << "Base::g(float) " << x << endl; }
     void h(float x){ cout << "Base::h(float) " << x << endl; }
};

class Derived : public Base
{
public:
     virtual	void f(float x){ cout << "Derived::f(float) " << x << endl; }
     void g(int x){ cout << "Derived::g(int) " << x << endl; }
      void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

void main(void)
{
Derived  d;
Base *pb = &d;
Derived *pd = &d;

pb->f(3.14f);	
pd->f(3.14f);	

pb->g(3.14f);	
pd->g(3.14f);	
 
pb->h(3.14f);	
pd->h(3.14f);	
}

/*
注意:
(1)函式Derived::f(float)覆蓋了Base::f(float)。
(2)函式Derived::g(int)隱藏了Base::g(float),而不是過載。
(3)函式Derived::h(float)隱藏了Base::h(float),而不是覆蓋。 
*/

執行結果:

Derived::f(float) 3.14 
Derived::f(float) 3.14
Base::g(float) 3.14
Derived::g(int) 3
Base::h(float) 3.14
Derived::h(float) 3.14

再看下面這個例子:

class Base
{
public:
	void f(int x);
};

class Derived : public Base
{
public:
	void f(char *str);
};

void Test(void)
{
	Derived *pd = new Derived;
	pd->f(10);	 // 出錯
}

隱藏規則至少有兩個存在的理由:
1.寫語句pd->f(10)的人可能真的想呼叫Derived::f(char *)函式,只是他誤將引數寫錯了。有了隱藏規則,編譯器就可以明確指出錯誤。否則,編譯器會靜悄悄地將錯就錯,程式設計師將很難發現這個錯誤,留下禍根。
2.假如類Derived有多個基類(多重繼承),有時搞不清楚哪些基類定義了函式f。如果沒有隱藏規則,那麼pd->f(10)可能會呼叫一個出乎意料的基類函式f。儘管隱藏規則看起來不怎麼有道理,但它的確能消滅這些意外。

將程式進行如下修改就正確了

class Base
{
public:
	void f(int x);
};

class Derived1 : public Base
{
public:
	void f(char *str);
	void f(int x) { Base::f(x); }
}; 

void Test1(void)
{
	Derived1 *pd = new Derived1;
	pd->f(10);	 // 正確
}