2015-04-12 130 views
2

我偶然發現從派生類派生類派生,並發現我的知識存在差距。我一直生活在這個可能的世界 - 直到現在。相反,std::bad_cast被拋出。這裏發生了什麼?Can not dynamic_cast sideways

#include <iostream> 

class Base 
{ 
protected: 
    int x_; 

public: 
    Base(int x) : x_(x) {} 
    virtual ~Base() = default; 
    int x() const { return x_; } 
    virtual void setX(int x) = 0; 
}; 

class Editable : public Base // class implements setters 
{ 
public: 
    Editable(int x) : Base(x) {} 
    void setX(int x) { x_ = x; } 
}; 

class ReadOnly : public Base // class implements empty setters 
{ 
public: 
    ReadOnly(int x) : Base(x) {} 
    void setX(int x) {} 
}; 

int main() 
{ 
    Editable editable(4); 
    ReadOnly &readOnly = dynamic_cast<ReadOnly&>(editable); // std::bad_cast 
} 
+2

當然,它可以側身投(儘管這不是真的你正在使用的意義上),但事情你實際上是鑄造仍須是一個'ReadOnly'(或從它派生的類)... –

+0

「與其他類型轉換不同,dynamic_cast涉及運行時類型檢查,如果綁定到該指針的對象不是目標類型的對象,則失敗並且該值爲0.如果它在失敗時是引用類型,則會拋出bad_cast類型的異常。「 – SChepurin

回答

4

這是當人們說dynamic_cast可以側身投是什麼意思:

struct A { virtual ~A() = default; }; 
struct B { virtual ~B() = default; }; 
struct D : A, B {}; 

B* pb = new D(); 
A* pa = dynamic_cast<A*>(pb); // OK 

即,它可以讓你蒙上了B*A*如果指針指向的東西是源自AB。爲了演員成功,仍然必須有一個A子對象指向指向的指針(如果您要轉換爲引用類型,則必須有指向綁定的引用)。

在你的情況下,e是一個Editable。那裏沒有ReadOnly子對象。所以演員失敗了。

+0

謝謝,所以問題是我對側身鑄造的誤解。我將從'ReadOnly'繼承'Editable'來獲得相同的功能並消除'Base'。 – LogicStuff

+0

@LogicStuff:如果您使用該解決方案,您可能會將名稱從'ReadOnly'更改爲'Readable',因爲'Editable'的實例顯然不是隻讀的! – Hurkyl

2

你不是在側身投射。
您正在從一個派生的基地投射到另一個基地。

讓我們假設你的演員成功了,並且在ReadOnly類中有一個名爲readOnlyInt的公共int成員。

編譯器如何執行readonly.readOnlyInt
鑄造ReadOnly &沒有readOnlyInt因爲它實際上是一個Editable

鑄造橫盤涉及多重繼承結構&看起來是這樣的:

class A { 
    virtual ~A() {} 
}; 

class B { 
    virtual ~B() {} 
}; 

class C : public A, public B { 
}; 

int main() { 
    B *b = new C(); 
    A *a = dymanic_cast<A *>(b); 

    return 0; 
}