2009-02-26 23 views
5

私は基本クラスと派生クラスを持っています。各クラスには.hファイルと.cppファイルがあります。dynamic_castは失敗します

私は、次のコードでは、派生クラスに基底クラスのオブジェクトのはdynamic_castをしています:いくつかの奇妙な理由から

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) 
} 

Hファイル:

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

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

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

のcppファイル、キャストは失敗します(NULLを返します)。しかし、派生クラスのコンストラクタの実装を.hから.cppファイルに移すと、キャストは成功します。

何が原因なのですか?

コンパイラはLinux-SUSEのgcc 3.1です。ところで、私はこのプラットフォームでのみこの動作を参照し、同じコードはVisual Studioで正常に動作します。

+0

多分それはgccの3.1のバグだと正常に動作しますか? "-fdump-class-hierarchy"オプションを試して、2つのクラスのvtableを作成するかどうかを確認してください。 –

答えて

5

投稿されたコードは、基本クラスに仮想関数(litbが指摘されている)を持っていれば、失敗しません。

しかし、現状のコンパイラでは、「基本クラスはポリモーフィックではありません」という種類のエラーを生成すると思います。そうしないと、おそらく問題にならないでしょう。

私が考えることができる唯一のことは、奇妙なバグのためにすべてがインラインになり、vtableが生成されないということです。しかし、コンストラクタをC++ファイルに置くと、コンパイラはすべてをインライン化しないようにし、vtableの作成をトリガーして、キャストを動作させます。

しかし、これは非常に野生の推測である、と私はすべてのコンパイラはそれで、このような間違いを持っ​​ているでしょうとは思わない(?)

をあなたは明確な答えをしたい場合は、より多くのコードを投稿してください。そしてコンパイラ/プラットフォームが使われました。

編集:私はあなたが、少なくとも基地から派生派生するべきだと思います更新されたコード

を見て;)(私はタイプミスだと仮定)

しかし、コードを見た後、唯一のことは私が考えることができますgcc(間違って)がすべてをインライン化し、Derivedのvtableを生成しないということです。それは価値があるため、これはgccでコンパイルされた状態で実行されます。

3.1今は7歳以上です。アップグレードする可能性がある場合は、それを試してみてください。

7

Baseに仮想機能はありますか?そうでなければ動作しません。それ以外の場合は、その仮想を仮想にします。

答えを削除した他の人に既に尋ねられているかどうかは分かりませんが、私はそれが違うと信じています:拠点のコンストラクタからdynamic_castをやっていますか?もしそうなら、それは動作しません。コンパイラは、Baseが最も派生した型であると考えます。仮想関数を呼び出すと同様に、Baseのバージョンを呼び出すことになります。

+0

Baseに仮想関数があります。 –

3

デストラクタを仮想にして、少なくとも1つの仮想メソッドを.cppファイルに配置します。

一部のコンパイラ(gcc参照)は、最初に検出された非インライン仮想メソッド本体を探し、それを使用して仮想メソッドテーブルをどこに配置するかを決定します。.cppファイル内にボディを持つ仮想メソッドがない場合、仮想メソッドテーブルは作成されません。

dynamic_castを動作させるには、少なくとも1つの仮想メソッドが必要です。動的キャストはテーブルを使用して型情報を把握し、仮想メソッドがない場合はテーブルを作成しません。

サブクラス化が必要なクラスがあり、そのクラスにデストラクタがある場合、またはそのクラスにデストラクタを持つクラスであるインスタンス変数がある場合は、デストラクタを仮想にすることができます空の身体)。そうしないと、サブクラスのインスタンスに対して期待されるクリーンアップは発生しません。

0

これはVisual C++で行っていますか?私はこれを動作させるためにコンパイラ設定でランタイムタイプ情報(RTTI)を有効にする必要があると思います。

これが間違っている場合は、私に火を付けないでください。私がC++を使ってからしばらくしています!

0

あなたのコードを見ると、私はいかなる継承も見ません。あなたはそれを忘れましたか?派生したものは何に由来するものでもありません。

0

投稿したコードでDerivedはBaseから派生したものではありません。

編集:はFYI、変更されたコードをg ++ 3.4.5

関連する問題