【初級】C++中子類物件轉型為父類物件時,編譯器默默做了什麼?
阿新 • • 發佈:2019-01-01
被問及C++中將子類物件轉型為父類物件時,會發生什麼?大部分人可能會回答說:子類成份會被"閹割",也就是說它不再具有子類特性。確實是這樣,不過我想知道編譯器是怎麼處理“閹割”的。請看如下程式碼,
Child chd;
Base b0(chd);
Base b1 = chd;
Base b2;
b2 = chd;
很明顯,b0和b1都是通過呼叫Base的拷貝建構函式來完成構建的。對於b2,編譯器首先呼叫Base的預設建構函式進行構造,然後呼叫Base的賦值運算子來把子類中的父類成份賦值給b2。
再來看看下面的程式碼:
class Base { public: Base() { i = 0; printf("Base()\n"); } Base(const Base & base) : i(base.i) { printf("Base copy.\n"); } Base& operator=(const Base &base) { printf("Assignment.\n"); return *this; } void Inc() {++i;} void print() {printf("%d\n",i);} int i; }; class Child : public Base { }; int main() { Child chd; chd.Inc(); // add 1 Base base(chd); // copy base.print(); static_cast<Base>(chd).Inc(); chd.print(); // 打印出1 ((Base)chd).Inc(); chd.print(); // 打印出1 return 0; }
很明顯,main()函式中的第一個列印語句會輸出1,為什麼第二,三個也輸出1,不是對i作加1操作了嗎。原來上面的static_cast<Base>(chd).Inc()或者 ((Base)chd).Inc()會被編譯器轉化為如下程式碼:
Base temp(chd);
temp.Inc();
是的,編譯器通過拷貝建構函式構造出一個臨時的Base物件,然後對那個臨時物件進行加1操作,所以並沒有改變chd物件的狀態。
總結:編譯器“閹割”子類物件是通過拷貝建構函式或賦值運算子來完成的。注意轉型中臨時物件可能產生。