6

基本クラスと派生クラスがあります。各クラスには、.h ファイルと .cpp ファイルがあります。

次のコードで、基本クラス オブジェクトの派生クラスへの 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 を返します)。ただし、派生クラスのコンストラクターの実装を .h から .cpp ファイルに移動すると、キャストは成功します。

何が原因ですか?

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

4

6 に答える 6

8

Baseに仮想機能はありますか?それ以外の場合は機能しません。他に何もない場合は、そのdtorを仮想化します。

彼の答えを削除した他の人からすでに尋ねられたかどうかはわかりませんが、それは何か違うと思います:あなたは基地のコンストラクターからdynamic_castをやっていますか?もしそうなら、それはうまくいきません。コンパイラは、仮想関数を呼び出す場合と同様に、Baseが最も派生した型であると見なし、最終的にBaseのバージョンを呼び出すことになります。

于 2009-02-26T12:44:16.487 に答える
6

基本クラスに仮想関数がある場合(litbが指摘したように)、投稿されたコードは失敗しないはずです。

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

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

しかし、これは非常に当て推量であり、どのコンパイラもそのような間違いを犯すとは思いません (?)

明確な答えが必要な場合は、さらにコードを投稿してください。そして、使用されるコンパイラ/プラットフォーム。

EDIT:更新されたコードを見る

少なくとも Derived from Base を派生させるべきだと思います ;) (それはタイプミスだと思います)

しかし、コードを見た後、私が考えることができる唯一のことは、gcc が (間違って) すべてをインライン化し、Derived の vtable を生成しないということです。価値があるのは、これは gcc 4.0 でコンパイルされた問題なく動作することです。

3.1 は今では 7 年以上前のものです... アップグレードする可能性があれば、私はそれを選びます。

于 2009-02-26T13:21:03.060 に答える
4

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

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

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

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

于 2009-02-26T13:27:19.100 に答える
0

あなたが投稿したコードでは、DerivedはBaseから派生していません。

編集: 参考までに、変更されたコードはg++3.4.5で正常に動作します

于 2009-02-26T14:36:31.257 に答える