類的constructor和繼承 :
子類不能繼承父類的constructor,只能調用父類的constructor,如果子類沒有聲明constructor,當構造子類的實例時,將執行其默認構造函數,該默認構造函數將會首先調用父類的默認構造函數,若父類沒有默認構造函數,那麼只好匹配默認參數的constructor。
子類可以直接訪問父類的保護數據成員,但是這種方法並不好,最好通過父類的接口(member functions)來對其進行訪問。原因是一但父類出現了問題,只用修改父類。
在構造一個子類的實例時,完成其父類部分的構造由父類的constructor完成,而且總是從父類的構造開始的。
virtual和polymorphism :
當子類重載了父類的成員函數是:
class A
{
public:
void fun(){ }
};
class B : public A
{
public:
void fun(){ }
};
void main ()
{
A a;
B b;
a.fun();
b.fun();
}
各自調用自己的fun();只有當B沒有定義自己的fun()時b的fun()才爲A中定義的版本。但是如果:
class A
{
public:
void fun(){ }
};
class B : public A
{
public:
void fun(){ }
};
void Get(A & x)
{
x.fun();
}
void main()
{
A a;
B b;
Get(a);
Get(b);
}
因爲B爲A的子類,所以Get(A&)可以接受以上兩種參數,Get(a)應該調用A的fun(),Get(b)應該調用B的fun(),但是生成exe後,函數調用的fun就會隨實際的參數變化而變化,故會發生紊亂。因而引入polymorphism。能依據類型確定調用那個函數的能力叫polymorphism,或者late binding,反之爲early binding。
用virtual關鍵字賦予member function具有polymorphism,在默認情況下編譯器是early binding;只有看到virtual時才進行late binding,父類聲明polymorphism後,會帶給子類(省略)。
若父類和子類的函數返回類型函數名參數類型有一樣不一樣,即使聲明virtual也無濟於事,編譯器照樣進行late binding(因爲polymorphism的本質就是同一個函數的多種行爲,已經不是同一個函數談何多態?)。但有種例外:父類的函數返回父類的指針或引用,子類返回子類的指針或引用,但其他必須一樣,可以進行late binding。
應該儘量將類的成員函數聲明爲virtual函數,有好無壞。virtual函數針對類的member functions而言的。static && inline && constructor不能爲virtual。destructor最好爲virtual,原因是爲了防止內存泄露。
沒事寫了些代碼做實驗:
父類聲明virtual其他和子類一樣:通過對象和全局函數一樣:父類實例調父類的函數,子類的調子類的,與調用順序無關。
將父類的virtual移到子類對應的函數前:通過對象調用:各自調用各自的,與調用順序無關。
通過全局函數調用:兩個都調用父類的,與調用順序無關。
父類子類都不加virtual:通過對象調用:各自調各自的,與調用順序無關
通過全局函數調用:兩個都調用父類的
都加virtual就不用試了。
關於抽象類:
抽象類不能進行實例化,其主要作用是被繼承,抽象類至少有一個純虛函數(pure virtual function),純虛函數在子類裏未被重載前仍然是純虛函數,故子類也仍然是抽象類。抽象類不能實例,但是可以聲明其指針或引用