0

私はすでに実際に働いている何かの背後にある理論を確認しようとしています. 機能がさまざまな dll に分割されているため、完全なセットアップはややゆがんでいますが、状況を説明します。

class __declspec( dllexport ) BaseClass
/** This class' definition is available to everything,
 *  via .h file, .dll and .lib. */
{
    protected:
        std::string name;

    public:
        std::string GetName();
        /** This is implemented in BaseClass, and just returns this->name. */
}

class DerivedClass: public BaseClass
/** This class is created within the executable, but is not 'visible' to other
 *  dlls - either through .h files, .lib, or anything else. */
{
    public:
        DerivedClass();
        /** This sets this->name based on its own propertied. */
}

このアップキャストは機能しますが、DerivedClass の定義へのフル アクセスが必要です。

void* pointer;
DerivedClass* derived_pointer = reinterpret_class<DerivedClass*>(pointer);
BaseClass* base_pointer = dynamic_cast<BaseClass*>(derived_pointer);
base_pointer->GetName();

ただし、以下は機能しません。

void* pointer;
BaseClass* base_pointer = reinterpret_class<BaseClass*>(pointer);
base_pointer->GetName();

この問題を回避するために、インターフェイスを実装しました。

class __declspec( dllexport ) IBaseClass
/** Fully virtual 'interface' class, in same file as BaseClass. */
{
    public:
        virtual std::string GetName() = 0;
}

class __declspec( dllexport ) BaseClass: public IBaseClass
/** This class' definition is available to
 *  everything, via .h file, .dll and .lib. */
{
    protected:
        std::string name;

    public:
        std::string GetName();
        /** This is implemented in BaseClass, and just returns this->name. */
}

class DerivedClass: public BaseClass
/** This class is created within the executable, but is not 'visible'
 *  to other dlls - either through .h files, .lib, or anything else. */
{
    public:
        DerivedClass();
        /** This sets this->name based on its own propertied. */
}

そして今、次のコード機能します:

void* pointer;
IBaseClass* ibase_pointer = reinterpret_class<IBaseClass*>(pointer);
ibase_pointer->GetName();

完全に仮想化されたクラスへのキャストは特殊なケースであると誰かが私に言った記憶があいまいですが、その理由を思い出せず、ウェブ上でそれについて何かを見つけることもできません。

助けてください - なぜ私のコードは機能するのですか?!

4

1 に答える 1

1

これはクラス レイアウトに完全に依存しており、これは実装定義であり、依存することはできません。特に MSVC の場合、クラス レイアウトの入門としてはhttp://www.openrce.org/articles/full_view/23/d1reportSingleClassLayoutを参照してください。フラグを使用してクラス レイアウトを要求できることを知っておくとよいでしょう。

あなたの場合、最初のBaseClassものには仮想メンバーがないため、DerivedClass指定されていない場所に配置されます。それ以外の場合は、最初に動作することが期待されるので、仮想DerivedClassメンバーがいくつかあると思います。仮想メンバーがある場合は、次のようになります。BaseClassDerivedClassreinterpret_cast

+--------------------+
|DerivedClass vtable |
|BaseClass::name     |
|DerivedClass members|

インターフェイス IBaseClass を追加しても何も変わりません。DerivedClass は引き続き次のようにレイアウトされます。

+--------------------+
|DerivedClass vtable |
|BaseClass::name     |
|DerivedClass members|

ただし、DerivedClassvtable は vtable で始まりますIBaseClass

+---------------------+
|IBaseClass::GetName  |
|DerivedClass virtuals|

DerivedClassそのため、 vtableを介した呼び出しが機能します。

于 2012-07-12T15:52:50.767 に答える