C++ 多型的一些注意點
阿新 • • 發佈:2022-03-04
virtual
對於虛方法(virtual method),如果一個方法是通過引用或者指標而不是物件呼叫的,它將確定使用哪一種方法。如果沒有使用關鍵字virtual,程式將根據引用型別或指標型別選擇方法;如果使用了virtual,程式將根據引用或指標指向的物件的型別來選擇方法。
基類通常宣告虛解構函式
這樣做是為了確保釋放派生物件時,按正確的順序呼叫解構函式。如果不是虛的,那麼銷燬指向派生類物件的基類指標在銷燬的時候只會呼叫基類的解構函式,而不會呼叫派生類的,從而導致資料無法被正確析構。如果是虛的,那麼將先呼叫派生類的解構函式,然後再自動呼叫基類的解構函式。
靜態聯編和動態聯編
函式名聯編:將原始碼中的函式呼叫解釋為特定的函式程式碼塊;
在C++中,由於函式過載的緣故,這項任務更復雜,編譯器必須乍看函式引數及函式名才能確定使用哪個函式。
C/C++編譯器可以在編譯過程完成上述聯編。
靜態聯編(早起聯編):在編譯過程中完成的聯編;
但虛擬函式的存在使得這項工作變得更加複雜,有虛擬函式的情況下,使用哪一個函式是不能在編譯時確定的,應為編譯器不知道使用者將選擇哪種型別的物件,所以編譯器必須生成能夠在程式執行時選擇正確虛擬函式的程式碼。
動態聯編(晚期聯編):在程式執行時進行的聯編。
向上強制轉換(upcasting):將派生類引用或指標轉換為基類引用或指標;(不需要顯式型別轉換)
向下強制轉換(downcasting):將基類指標或引用轉換為派生類指標或引用;(需要強制型別轉換)
Derived a;
Base *p1 = &a; // OK
Base &p2 = a; // OK
Base b;
Derived *p3 = &b; // Wrong
Derived *p4 = (Base *)(&b); // OK
向上強制轉換(upcasting)可以將派生類引用或指標轉換為基類引用或指標並隱式呼叫派生類或基類方法,此時就需要動態聯編;
class B { virtual void do_f(); // private member public: void f() { do_f(); } // public interface }; struct D : public B { void do_f() override; // overrides B::do_f }; int main() { D d; B* bp = &d; bp->f(); // internally calls D::do_f(); }
比較 | 效率 | 處理階段 |
---|---|---|
動態聯編 | 需要跟蹤指標或引用,有額外開銷 | 執行時 |
靜態聯編 | 效率更高 | 編譯時 |