2009-02-26 37 views
5

我有一個基類和一個派生類。每個類都有一個.h文件和一個.cpp文件。dynamic_cast失敗

,我在下面的代碼做dynamic_cast的基類對象的派生類:

.h文件:

class Base 
{ 
    public: 
    Base(); 
    virtual ~Base(); 
}; 

class Derived : public Base 
{ 
    public: 
    Derived(){}; 
    void foo(); 
}; 

class Another 
{ 
    public: 
    Another(){}; 
    void bar(Base* pointerToBaseObject); 
}; 

cpp文件:

Base::Base() 
{ 
    //do something.... 
} 
Base::~Base() 
{ 
    //do something.... 
} 
void Derived::foo() 
{ 
    Another a; 
    a.bar(this); 
} 
void Another::bar(Base* pointerToBaseObject) 
{ 
    dynamic_cast<Derived*>(pointerToBaseObject) 
} 

從某種奇怪的原因,投射失敗(返回NULL)。但是,如果將Derived類的構造函數的實現從.h移動到.cpp文件,則轉換成功。

什麼能導致它?

編譯器是gcc 3.1,在Linux-SUSE上。順便說一句,我只在這個平臺上看到這種行爲,並且相同的代碼在Visual Studio中正常工作。

+0

也許是用gcc 3.1中的錯誤?嘗試「-fdump-class-hierarchy」選項,看看它是否爲你的兩個類創建了一個虛擬表格。 – 2009-02-26 15:37:42

回答

5

發佈的代碼不應該失敗,前提是您在基類中有一個虛函數(如litb指出的那樣)。

但我相信每個當前的編譯器都會生成一個「基類不是多態」的錯誤類型,如果沒有的話,這樣可能不會是問題。

我唯一能想到的是,由於一些奇怪的錯誤一切都被內聯,並沒有生成vtable。但是,如果將構造函數放在C++文件中,編譯器將決定不內聯任何東西,從而觸發創建一個vtable,從而導致您的演員工作。

但是,這是非常百搭的猜測,我不認爲任何編譯器將在它這樣的錯誤(?)

如果你想有一個明確的答案,發佈更多的代碼。並使用編譯器/平臺。

編輯:看到更新後的代碼

我想你應該至少中派生從鹼衍生;)(我想這是一個錯字)

但看到的代碼之後,我唯一能想到的是gcc(錯誤地)插入所有內容並且不會生成派生的vtable。對於它的價值,這運行良好編譯與海灣合作委員會4.0

3.1已超過7歲,現在...如果有任何可能性升級我會去爲它。

7

你在Base中有沒有虛函數?否則它將無法工作。如果沒有別的,使其虛擬。

不知道是否已經有其他人問過他刪除了他的答案,但我相信它有些不同:你是否正在從基地的構造函數中做dynamic_cast?如果是這樣,那是行不通的。編譯器會認爲Base是派生類型最多的,類似於當你調用一個虛函數時,它最終調用Base的版本。

+0

我在Base中有虛擬函數。 – 2009-02-26 12:46:26

3

使析構函數爲虛擬,並將它(或至少一個虛擬方法)放在.cpp文件中。

某些編譯器(閱讀:gcc)查找首次遇到的非內聯虛擬方法主體並使用它來決定放置虛擬方法表的位置。如果在.cpp文件中沒有任何具有主體的虛擬方法,則不會創建虛擬方法表。

您必須至少有一個virtual_cast工作的虛擬方法。動態轉換使用表格來確定類型信息,如果沒有虛擬方法,則不會創建表格。

如果你有一個你期望被子類化的類,它有一個析構函數,或者如果類有任何具有析構函數的類的實例變量,那麼你真的想讓你的析構函數變爲虛擬的(即使它具有一個空的身體)。否則,你期望的清理不會發生在子類實例上。

0

你在做Visual C++嗎?我認爲您必須在編譯器設置中啓用運行時類型信息(RTTI)才能使其正常工作。

如果我弄錯了,請別激怒我。從我使用C++開始已經有一段時間了!

0

在查看您的代碼時,我沒有看到任何繼承。你忘了這麼做嗎?派生不是來自任何東西。

0

在您發佈的代碼中Derived不是從Base派生的。

編輯:僅供參考,修改後的代碼工作正常使用g ++ 3.4.5