派生類的對象都含有基類對象作為其一部分,我們可以將指向派生類型的引用轉換為指向它的基類型的引用,像轉換指針一樣,我們可以用派生類的對象初始化或賦值基類對象,反之卻不行。class base{
public:
};
class derived:public base{
public:
};
int main(void) {
derived obj_d;
base obj_b=obj_d;//賦值運算符
base obj_b2(obj_d);//用派生類對象初始化
derived &ref_d=obj_d;
base &ref_b=ref_d;
base &ref_b2(ref_d);
cout<<"end in main\n";
return EXIT_SUCCESS;
}
程序編譯沒有錯誤,只是會提示ref_b,ref_b2沒有使用,如果反過來轉換基類對象或引用為派生類型的則會報錯。
實際上,這里編譯器并沒有將派生類對象或引用“轉換”為基類型的,只是用派生類對象中的基類部分初始化或賦值基類對象,引用方面,將派生類基類部分的地址傳遞給基類型的引用。
前面在虛函數實例時,看到將派生類對象傳遞給參數為基類型引用的函數,這時傳遞的是地址,實參的派生類對象還是派生類對象。
如果是參數為基類對象的函數,情況有所不同,實參派生類對象的基類部分會被復制給一個函數體內建立的臨時的基類對象。
當我們用派生類對象初使化或賦值基類對象時,有兩種可能:
1.基類中定義了相應的構造函數和重載了賦值運算符,這時將會按照相應的函數進行
class derived;
class base{
public:
base(const derived&);
base& operator=(derived &);
};
2.基類中并沒有定義相關的函數,與情況1相比,這種情況更為常見。
通常基類中會有考構,其參數為const 基類型引用,考構會幫我們完成派生類對象初始化或賦值基類型對象,其中發生指向派生類的引用轉換為基類型的引用。開頭的示例程序:
base obj_b=obj_d;//賦值運算符
base obj_b2(obj_d);//用派生類對象初始化,調用的構造函數
派生類中的基類部分好像被“切割”(slice down)下一樣,賦值給基類對象。
派生類-基類 轉換后的成員訪問問題
如果是公有派生,轉換后,可以訪問基類對象的相應成員,如果是保護或私有派生則不可。
class base{
public:
int pub;
protected:
int pro;
};
class derived:public base{
public:
};
int main(void) {
derived obj_d;
base obj_b=obj_d;//賦值運算符
cout<<obj_b.pub<<" "<<endl;
cout<<"end in main\n";
return EXIT_SUCCESS;
}
程序沒有任何問題,輸出結果為一隨機值,因為我們沒有定義任何構造函數為數據成員初始化。
如果將派生類型變為保護或私有
class derived:protected base{
public:
};
編譯報錯 `base' is an inaccessible base of `derived'
而且,私有派生時,其后續派生的類是不可轉換為基類型的,保護派生可以。
基類-派生類 的轉換
無論是用基類對象還是引用初始化派生類對象或引用都是不可以的,基類對象其所占的內存空間中并沒有派生類所定義的只屬于它自己的那一部分。即使是有一個基類型的引用,其此時正好指向一個派生類對象,我們也不可將其轉換為派生類型的引用,因為編譯時編譯器檢查的是靜態類型。