2012-10-07 67 views
1

我改變了我的C++基類爲protected繼承和我的dynamic_cast(s)停止工作。爲什麼受保護的繼承導致dynamic_cast失敗?

爲什麼要改變繼承爲protected改變dynamic_cast的行爲?

struct Base { 
    static Base *lookupDerived(); // Actually returns a Derived * object. 
}; 

struct Derived : protected /* Switch this to public to get it working */ Base { 
static void test() { 
    Base *base = lookupDerived(); 

    if (dynamic_cast<Derived *>(base)) { 
     std::cout << "It worked (we must be using public inheritance)." << std::endl; 
    } else { 
     std::cout << "It failed (we must be using protected inheritance)." << std::endl; 
    } 
}; 

回答

3

作爲外部用戶,您無法訪問某個班的受保護或私人成員。這同樣適用於受保護或私有繼承。一個班級的作者不希望外部用戶訪問受保護的/私人的父級,而不希望外部用戶訪問受保護的/私人的成員。

原因之一:假設父類有一個非虛擬的析構函數。從基類指針中刪除實例派生類會導致未定義的行爲。使父類保護/私人意味着你不能這樣做(見腳註)。

另一個原因:假設有問題的類的作者不希望外部用戶訪問父類的公共成員。可以使用公共繼承(is-a)並將這些公共接口降級爲受保護或私有接口,但這會違反Liskov替換原則。受保護或私人繼承不是is-a的關係。這些公共方法通過受保護或私有繼承進行保護或私有。 Liskov替換沒有問題,因爲受保護/私有繼承不是is-a

腳註:有一個醜陋的方法:使用C風格的演員。外部用戶可以將一個 派生類指針強制轉換爲基類指針,即使基類不可訪問。對我來說,這是編譯​​的又一個理由。

1

當你改變你的繼承保護,你的兩個類之間的關係是從物體的外表隱藏。

1

私有(或受保護的)繼承在語義上與公有繼承不同。 這不是一個「是-A」的關係,而是「按照」關係實施的。這意味着你不能使用基類作爲派生對象的句柄。