C++ 虛擬函式;過載與覆蓋;虛繼承
1.什麼是虛擬函式
簡單地說,那些被virtual關鍵字修飾的成員函式,就是虛擬函式。虛擬函式的作用,用專業術語來解釋就是實現多型性(Polymorphism),多型性是將介面與實現進行分離;用形象的語言來解釋就是實現一共同的方法,但因個體差異而採用不同的策略。虛擬函式主要通過虛擬函式表(V-Table)來實現。
2.什麼是純虛擬函式
純虛擬函式相當於基類只提供介面而不定義具體實現,在函式聲明後加=0,如:
virtual void Eat() = 0;
3.純虛擬函式和虛擬函式的區別
虛擬函式在派生類裡面也可以覆蓋,也可以不覆蓋的,直接使用基類的實現;但純虛擬函式必須在派生類中實現,因為它只提供了一個介面。
4.1成員函式被過載的特徵
(1)相同的範圍(在同一個類中);
(2)函式名字相同;
(3)引數不同;
(4)virtual 關鍵字可有可無。
4.2“覆蓋”是指派生類函式覆蓋基類函式,特徵是:
(1)不同的範圍(分別位於派生類與基類);
(2)函式名字相同;
(3)引數相同;
(4)基類函式必須有virtual 關鍵字。
4.3“隱藏”是指派生類的函式遮蔽了與其同名的基類函式,特徵是:
(1)如果派生類的函式與基類的函式同名,但是引數不同,此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。
(2)如果派生類的函式與基類的函式同名,但是引數相同,但是基類函式沒有virtual 關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)。
static成員函式不能覆蓋和隱藏
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; }
};
int main()
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
pb->f(3.14f); // Derived::f(float) 3.14(覆蓋)
pd->f(3.14f); // Derived::f(float) 3.14(覆蓋)
pb->g(3.14f); //Base::g(float) 3.14(非虛擬函式,直接呼叫基類函式)
pd->g(3.14f); //Derived::g(int) 3(最佳匹配應該是float,但是因為“隱藏”了所以只能呼叫派生類函式)
pb->h(3.14f); //Base::h(float) 3.14(非虛擬函式,直接呼叫基類函式)
pd->h(3.14f); //Derived::h(float) 3.14(隱藏)
return 0;
}
5.虛繼承和虛基類
虛擬繼承是多重繼承中特有的概念。虛擬基類是為解決多重繼承而出現的。如:類D繼承自類B1、B2,而類B1、B2都繼承自類A,因此在類D中兩次出現類A中的變數和函式,這時會產生二義性。為了解決二義性,同時為了節約記憶體,B1、B2對A的繼承定義為虛擬繼承,而A就成了虛擬基類,這樣D中就只有一份A中的變數和函式。實現的程式碼如下:
class A;
class B1:public virtual A;
class B2:public virtual A;
class D:public B1,public B2;