2

C++ デストラクタの動作について質問がありましたが、何よりも好奇心からでした。私は次のクラスを持っています:

Base.h

class BaseB;

class BaseA
{
    public:
        virtual int MethodA(BaseB *param1) = 0;
};

class BaseB
{
};

Imp.h

#include "Base.h"
#include <string>

class BImp;

class AImp : public BaseA
{
    public:
        AImp();
        virtual ~AImp();

    private:
        AImp(const AImp&);
        AImp& operator= (const AImp&);

    public:
        int MethodA(BaseB *param1) { return MethodA(reinterpret_cast<BImp *>(param1)); }

    private:
        int MethodA(BImp *param1);
};

class BImp : public BaseB
{
    public:
        BImp(std::string data1, std::string data2) : m_data1(data1), m_data2(data2) { }
        ~BImp();
        std::string m_data1;
        std::string m_data2;

    private:
        BImp();
        BImp(const BImp&);
        BImp& operator= (const BImp&);
};

問題は、このコードではすべてが問題なく動作することです。しかし、AImp::MethodA の呼び出しで BImp 仮想のデストラクタを作成すると、クラス BImp のデータ (m_data1 および m_data2) が初期化されていないように見えます。構築時に含まれているデータが正しいことを確認したので、これの背後にある理由は何だろうと思っていました...

乾杯!

編集: param1 は、実際には MethodA の B への参照でした。実際のコードを少しサニタイズしすぎたようです。

Edit2: 2 つの異なるファイルを表示するために、コードを少し再配置しました。このコードがコンパイルされることをテストしました。ごめんなさい!

4

5 に答える 5

9

この場合のように、関連する型間でキャストする場合は、 ではなくorを使用する必要がありますstatic_castdynamic_castreinterpret_cast。これは、コンパイラがオブジェクト ポインター値をより派生した型にキャストする際にオブジェクト ポインターの値を調整する可能性があるためです。この場合、の結果reinterpret_castは未定義です。これは、ポインター値を取得するだけで、オブジェクトのレイアウトを考慮せずに別のオブジェクトであると見なすためです。

于 2009-12-20T23:06:29.113 に答える
2

MethodA は、そのパラメーターを値で受け取ります。これは、コピーが渡されたことを意味します (そして、コピーを破棄する必要があります)。これは、予想していなかった BImpl が破棄される理由についての私の最善の推測ですが、A のデストラクタの仮想または非仮想の性質がそれと関係がある可能性があるとは考えていません。

しかし、このコードはコンパイルできません。A で仮想関数を宣言する際にクラス B を使用しますが、B は後で定義されます。そして、そのキャストで何が起こっているのかわかりません-クラスタイプを reinterpret_cast することはできません。おそらく、問題を示すテストケースを作成して投稿した場合はどうでしょうか?

于 2009-12-20T23:03:07.733 に答える
1

このコードには多くの気の利いたものが含まれているので、どのような場合でも機能またはコンパイルされることに驚いています。

  • を参照する代わりに値でパラメータを渡すMethodA
  • ビアにキャストするB-悪い考えです!その方向にキャストする場合は、が最も安全です。BImpreinterpret_castdynamic_cast
  • BからBImpを取得する方法がわかりません。コンストラクターを呼び出しておらず、Bを受け入れるコンストラクターもありません。BImpのデフォルトのコンストラクターはプライベートであり、データがないB、まだデータがないBImp、BImpにキャストされても、データは提供されません。
于 2009-12-20T23:10:17.743 に答える
1

いくつかのコメント:

  • オブジェクトが削除されると、基本クラスの dtor だけでなく、派生クラスの dtor が呼び出されるように、基本クラスには仮想デストラクタが必要です。

  • MethodA が BaseB ポインターをパラメーターとして取り、そのポインターを BImp (BaseB の派生クラス) として再解釈するためだけに使用するのは危険です。BImp 以外の何かが MethodA に渡されるという保証はありません。BaseB オブジェクトだけが MethodA にあった場合はどうなるでしょうか? 潜在的に多くの悪いことがあると思います。

  • BImp を MethodA に渡すだけなので、コードは「問題なく動作する」と思います。BImp を MethodA に渡すだけの場合は、署名を意図と一致させます (これには、ひどい再解釈呼び出しを削除するという追加の利点があります)。

于 2009-12-21T17:00:14.163 に答える
0

コードの形式が正しくありません。有効な C++ ではありません。C++ 言語でreinterpret_castは、ポインター型、参照型の間でキャストして、ポインターから整数への変換を実行するためにのみ使用できます (どちらの方向でも)。

あなたのコードでは、 type から type に変換するために使用しようとしていreinterpret_castます。これは、C++ では明らかに違法です。コンパイラがこのコードを許可している場合は、何が起こっているのかを判断するために、コンパイラのドキュメントを参照する必要があります。BBImp

他の回答はすでに「スライス」について言及しています。これは、特定のコンパイラの特定の非標準動作に関する単なる推測に過ぎないことに注意してください。C++言語とは関係ありません。

于 2009-12-20T23:37:31.580 に答える