2016-02-27 21 views
2

我有關於多態性問題C++鑄造衍生指針或設計錯誤

using namespace std; 

class Base { 
public: 
Base(int v) { u = v; }; 
    virtual ~Base(){}; 
    int u; 
    void f() { /* operations on u */ }; 
}; 

template<class T> 
class Derived: public Base { 
public: 
    T t; 
    Derived() { } 
    void g() { std::cout << u; /* operations on t and u */ } 
}; 

int main() { 
    Base *b = new Base(1); 
    b->f(); 
    if (b->u == 1) { 
     Derived<int> *d = dynamic_cast<Derived<int> *>(b); 
     d->g(); 
    } 
    return 0; 
} 

隨着D->克()會有段錯誤。轉換後可以在Derived對象中訪問u嗎?這個程序的目的是構造一個未知類型的類(關於這個類的信息只有在類對象被構造後纔可用,例如一個讀取jpg文件的類,事先不知道深度信息)。還是有這種問題的設計模式?感謝您的任何提示。

+1

但'b' *不是'派生'對象,試圖做你所做的就是*未定義的行爲*。您可以查看序列化庫來查看它們如何處理這些情況,但通常的方法是保存一些元數據,以告知實際對象的實際類型和大小*。如果你看看例如[Microsoft MFC框架](http://www.sorting-algorithms.com/),它使用['DECLARE_DYNAMIC'](https://msdn.microsoft.com/en-us/library/ywz9k63y.aspx)宏以啓用更多運行時信息。 –

+0

請注意,如果轉換失敗,dynamic_cast將返回一個空指針,在本例中它將執行該指針。 –

回答

1

不,這是不可能的。

這是因爲您構建了Base的實例,而不是Derived的實例。你可能打算這樣做:

Base *b = new Derived<int>(); 

但是,這不會工作,因爲Base沒有一個默認的構造函數。

您將永遠無法使用此代碼實例化任何Derived<T>,因爲Derived會嘗試使用Base的默認構造函數,但它沒有。

dynamic_cast<T>不用於創建一個類的新實例,無線連接到現有的類。它用於解析超類或子類的現有實例,這與動態流程實例所屬的類相關。

2

您的代碼出現segfaults不是因爲在*b沒有Base::u但由於dnullptr和提領它調用未定義的行爲。根據規範要求,dynamic_cast<T*>(p)給你要麼

  • 指針屬於*pT對象,如果有一個或者
  • 一個nullptr

由於b未指向Derived<int>類型的對象,因此您將獲得nullptr。稍後,當您嘗試使用該nullptr時,您的程序會出現段錯誤。

請注意,如果你dynamic_cast來一個參考,行爲是不同的。 dynamic_cast<T&>(r)

  • 給你屬於rT對象(其中r是參考)或
  • throwstd::bad_cast類型的異常的參考,如果沒有這樣的對象。

因此,您通常會以以下任一方式使用dynamic_cast

  1. 如果你想測試動態類型的對象,做的東西與它時,它是有一定的class

    if (auto d = dynamic_cast<D*>(b)) 
        { 
        // We have a D object here (d != nullptr), use it. 
        d->use(); 
        } 
    else 
        { 
        // We don't have a D object (d == nullptr) here. 
        } 
    
  2. 如果你(想你)肯定知道的指針指向的對象(動態)型D

    dynamic_cast<D&>(*b).use(); 
    

在C ase,似乎你有一個約定,b->u == 1以某種方式應該暗示動態類型*bDerived<int>,所以你可能會考慮dynamic_cast來引用。 (如果沒有別的,它會給你一個比「分段錯誤」更有幫助的錯誤信息。)當然,現在你知道dynamic_cast的行爲,你可以擺脫那個「約定」並直接通過一個測試動態類型dynamic_cast指針。無論如何,您首先必須解決Sam Varshavchikanswer中描述的問題。

查看cppreference.com瞭解關於dynamic_cast的更多信息。

+0

對於(2),如果你確定知道你有'D',你可以使用'static_cast (* b)'。爲什麼有額外的開銷? (也許''dynamic_cast ()'在調試版本中) – Barry

+0

@Barry除非你涉及複雜的多重繼承,否則這是一個選項。但是在發佈代碼中保持完整性檢查似乎是合理的,除非演員代碼非常熱。 (並感謝您修復我的錯字。) – 5gon12eder