類成員函式的過載、覆蓋和隱藏區別
成員函式被過載的特徵
(1)相同的範圍(在同一個類中);
(2)函式名字相同;
(3)引數不同;
(4)virtual 關鍵字可有可無。
覆蓋是指派生類函式覆蓋基類函式,特徵是
(1)不同的範圍(分別位於派生類與基類);
(2)函式名字相同;
(3)引數相同;
(4)基類函式必須有virtual 關鍵字。
當派生類物件呼叫子類中該同名函式時會自動呼叫子類中的覆蓋版本,而不是父類中的被覆蓋函式版本,這種機制就叫做覆蓋。
派生類物件呼叫的是派生類的覆蓋函式
指向派生類的基類指標呼叫的也是派生類的覆蓋函式
基類的物件呼叫基類的函式
“隱藏”是指派生類的函式遮蔽了與其同名的基類函式,規則如下
(1)如果派生類的函式與基類的函式同名
(2)如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有virtual 關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)
f()函式屬於覆蓋,而g()與h()屬於隱藏。從上面的執行結果,我們可以注意到在覆蓋中,用基類指標和派生類指標呼叫函式f()時,系統都是執行的派生類函式f(),而非基類的f(),這樣實際上就是完成的“介面”功能。而在隱藏方式中,用基類指標和派生類指標呼叫函式f()時,系統會進行區分,基類指標呼叫時,系統執行基類的f(),而派生類指標呼叫時,系統“隱藏”了基類的f(),執行派生類的f(),這也就是“隱藏”的由來。
指向派生類的基類物件呼叫的是基類的被隱藏的函式
例:
#include<iostream.h>
class a
{
public:
void f(float x)
{
cout<<"a :: f(float)"<<endl;
}
virtual void g(int x)
{
cout<<"a :: g(int)"<<endl;
}
void h()
{
cout<<"a :: h()"<<endl;
}
};
class b:public a
{
public:
void f()//過載 不可以和a::f(float)過載(不在同一個類)
{
cout<<"b :: f()"<<endl;
}
void f(int x)
{
cout<<"b :: f(int)"<<endl;
}
void g(int x)//覆蓋a::g(int x) 引數相同,名稱相同,基類有virtual修飾
{
cout<<"b :: g(int)"<<endl;
}
void g(float x)//過載b::g() a::g(int) 名稱相同,引數不同
{
cout<<"b :: g(float)"<<endl;
}
void h(float x)//隱藏a::h() 引數不同,名稱相同,要呼叫a::h()必須將其轉換為基類
{
cout<<"b :: h(float)"<<endl;
}
};
int main()
{
a *p,z;
b *pb;
b x,y;
p=&x;
z.f(1.5);
z.g(1);
z.h();
cout<<"------------------"<<endl;
p->f(1);
p->g(1);
p->h();
cout<<"------------------"<<endl;
pb=&y;
pb->f(16.1);
pb->f(1);
pb->f();
cout<<"-----------------"<<endl;
pb->g(1);
pb->g(1.5f);
pb->h(1.2);
return 0;
}
a :: f(float)
a :: g(int)
a :: h()
------------------
a :: f(float)
b :: g(int)
a :: h()
------------------
b :: f(int)
b :: f(int)
b :: f()
-----------------
b :: g(int)
b :: g(float)
b :: h(float)
Press any key to continue
虛擬函式
l 虛擬函式是動態聯編的基礎。
l 是非靜態的成員函式。
l 在類的宣告中,在函式原型之前寫virtual。
l virtual 只用來說明類宣告中的原型,不能用在函式實現時。
l 具有繼承性,基類中聲明瞭虛擬函式,派生類中無論是否說明,同原型函式都自動為虛擬函式。
l 本質:不是過載宣告而是覆蓋。
l 呼叫方式:通過基類指標或引用,執行時會
根據指標指向的物件的類,決定呼叫哪個函式。
抽象類
virtual 型別 函式名(引數表)=0; //純虛擬函式
帶有純虛擬函式的類稱為抽象類
抽象類作用:
l 抽象類為抽象和設計的目的而建立,將有關的資料和行為組織在一個繼承層次結構中,保證派生類具有要求的行為。
l 對於暫時無法實現的函式,可以宣告為純虛擬函式,留給派生類去實現。
注意:
l 抽象類只能作為基類來使用。
l 不能宣告抽象類的物件。
l 建構函式不能是虛擬函式,解構函式可以是虛擬函式。