5

次のようなパブリック インターフェイスの階層があります。

struct ISwitchable {
    /* Obtain pointer to another implemented interface of the same instance. */
    virtual int switch(unsigned int interfaceId, void** pInstance) = 0;
};
struct IFoo : public ISwitchable { /* Methods */ };
struct IBar : public ISwitchable { /* Methods */ };
struct IFooBar : public IFoo, public IBar { /* Methods */ };

IFooBar を実装するクラスは、ファクトリ関数と共に dll に配置されます。クライアント コードは dll をロードし、ファクトリ関数を使用してクラス インスタンスを作成し、それをインターフェイスに従って使用します (これらはヘッダー ファイルとして提供されます)。

Scheme は、MSVC によって作成された dll と、Borland C++ Builder 6 によって作成されたクライアント コードで正常に動作します。

仮想継承を階層に導入します。

struct IFoo : public virtual ISwitchable { /* Methods */ };
struct IBar : public virtual ISwitchable { /* Methods */ };

そして、同じ状況 (MSVC による dll、Builder によるクライアント) で、クライアント コードがクラスのインスタンスを要求すると、乱雑な vtable でそれを取得します。

通常の継承にロールバックする以外に解決策はありますか?

4

4 に答える 4

8

ビルドされたクラスがコンパイラ間で互換性があると期待できるとは思いませんでした。Borland は、MSVC によって構築されたクラスを読み込んで相互運用できると主張していますか。もしそうなら、彼らにはバグがあるようです。私の知る限り、VTable の正確な構造については C++ の仕様に記載されていないため、コンパイラ間で動作することは期待されていません。

于 2009-06-24T14:25:22.147 に答える
7

C とは異なり、C++ にはクロスコンパイラ ABI がありません。コンパイラは、仮想継承 (および通常の継承) を自由に実装できます。

つまり、コンパイラ間での C++ 関数の呼び出しは、動作が保証されていません。見苦しいことは承知していますが、DLL を複数のコンパイラとうまくやり取りさせたい場合は、単純なextern "C"関数のセットと手動で作成した関数ポインターのテーブルを代わりに提供する方がよいでしょう。

注: COM オブジェクトの構築をサポートする (または構築するためのオプションがある) コンパイラは、オブジェクトのレイアウトがより制限されます。(MSVC++ の最近のバージョンでは、少なくともほとんどの場合、COM 準拠のオブジェクトが生成されることは知っていますが、仮想継承がカバーされているかどうかはわかりません。)

于 2009-06-24T14:29:00.250 に答える
0

私はそのvoid**議論にうんざりしている。voidポインタを使用すると、型情報が失われます。

多重継承を使用している場合は、型情報が重要になる可能性があります。検討:

class Foo { ... };
class Bar { ... };

class Both: public Foo, public Bar { ... };

内部的には、BothインスタンスのレイアウトがFooインスタンスの後にBarインスタンスが続くと仮定します。Foo*を期待するメソッドにBoth*を問題なく渡すことができます。埋め込まれたバーを指すようにポインターを調整する場合は、Bar*を期待するメソッドにBoth*を渡すこともできます。両方で作業していることがわかっているので、これを確実に行うことができます。

今:

Foo *foo = new Both(...);
Bar *bar = new Both(...);

void *p = foo;
void *q = bar;

Both *both = (which) ? (Both*)p : (Both*)q;

つまり、「両方」に割り当てるときに、pまたはqのいずれかを調整する方法をどのように知ることができますか?ボイドポインタを通過すると型情報が失われるため、できません。

この問題の変種は、あなたが抱えている問題に関連している可能性があります。

于 2009-06-24T18:21:26.820 に答える
-2

おそらくあなたの質問には答えないでしょう...しかし、多重継承を使用しないことを強くお勧めします(「恐ろしいダイヤモンド」と呼ばれます)。

于 2009-06-24T14:25:05.313 に答える