4

一般的なケースをカバーする既存の回答がありますが、それらは少しあいまいであり、これについて確認する必要があります.

検討:

  • 抽象基本クラス「インターフェース」から派生する既存の定義済みクラス。
  • クラスは、インターフェイスを介して互いに通信する複数の dll にコンパイルされるライブラリの一部です。

それから加えて:

  • 定義されたクラスの派生元となる 2 番目の「インターフェース」 (つまり、2 つのインターフェースを持つようになりました)。
  • 新しいインターフェイスによってアクセスされる、定義されたクラスへの新しい仮想メソッド。

このライブラリをリンクするすべての dll を再コンパイルする必要がありますか?それとも、新しいメソッドを使用する dll のみを再コンパイルする必要がありますか?

編集:

元のインターフェースは動的メソッドを公開していDynamic(int OP, void* args)ますが、新しいインターフェースにキャストする op を追加することは可能でしょうか?

COM は、既存のインターフェイスを破壊することなく、新しいインターフェイスをオブジェクトに追加する方法を教えてください。インターフェイスをスタックしたり、複数の継承を使用したりしますか???

これがどのように機能するかを説明しましょう。

静的にリンクされたライブラリ インターフェイス

In statically linked library

class Interface1
{
    virtual Method1() = 0;
    virtual Method2() = 0;
}
class NotReallyInterface2 : Interface1
{
    virtual Method1() = 0;
    virtual Method2() { // does something }
}

DLL内

In A.dll

Load statically linked library
class A : NotReallyInterface2
{
    virtual Method1() { // does something }
}

In B.dll

Load statically linked library
class B: NotReallyInterface2
{
     virtual Method1() { // does something different }
}

追加したい

class Interface3
{
     virtual Method3() = 0;
}

私の継承構造が次のように見えるため、ここでいくつかの問題があります。

[a.dll [ library : Interface1 < NotReallyInterface2 ] < A ]
[b.dll [ library : Interface1 < NotReallyInterface2 ] < B ]

だから怖い

[ a.dll [ library : Interface1 < NotReallyInterface2 ] < Interface3 < A ]

動作しません。

編集 2

だから私は自分の問題を見つけました。どうやら、他の dll と実行可能ファイルが my を参照しているようNotReallyInterface2です。これは、複数の dll と exe が同じ基本クラスを構築していることを意味します。したがって、これらの基本クラスの「コピー」が同期しなくなると、船はダウンします。つまり、 の単一のメソッド シグネチャを変更することはできませんNotReallyInterface2

これは、誰も参照NotReallyInterface2していなければ機能していたはずであり、私は今、答えからそれを理解し、全体が理にかなっています.

4

4 に答える 4

2

公式には、クラスを変更するには、そのクラスに関係するすべてのものを再コンパイルする必要があります。C++ 標準、およびほとんどのコンパイラがドキュメントを作成している場合、「クラス内で何かを変更するとどうなるか」に関しては何の保証もありません。

実際には、これを機能させるためにできることがいくつかあります。そして、間違いなくすべてを壊すことができることがあります。

2 番目のインターフェイス クラスは 2 番目の vtable を導入します。これは、両方のクラスを継承するクラスの違いを意味します。これはほぼ確実に「すべてを壊すカテゴリ」にあり、クラスの「コンテンツ」に関係するあらゆる場所でそのクラスを使用するあらゆる場所で問題が発生します。

代わりに、元のインターフェイス クラスから派生した新しいクラスを追加することは可能でしょうか?

したがって、代わりに:

 class Interface_A
 {
   public:
    virtual void func1();
    virtual int  func2();
    ...
 };

 class Interface_B
 {
   public:
    virtual int func6();
    ...
 };

 class myClass : public Interface_A, public Interface_B
 {
   ... 
 };

これを行う:

 class Interface_B : public Interface_A
 {
   public:
    virtual int func6();
    ...
 };


 class myClass : public Interface_B
 {
   ... 
 };

これにより、(ほとんどの場合) vtable が少し長くなり、残りのコードでより受け入れやすくなり、Interface_A の機能のみを使用するコードでは、まったく問題が発生しません。[コンパイラが賢明な仕事をすることを前提としています-標準では、そうする場合、コンパイラが「すべてを台無しにする」ことを依然として許可しています。しかし、私は以前、システムの他の部分に依存する「変更されていない」コードがたくさんある会社で働いていました。

于 2013-08-08T16:33:34.470 に答える
1

新しいインターフェイスを追加すると、vtable のレイアウトを変更する追加の仮想メソッドが追加されます (仮想メソッド呼び出しをルーティングするための内部コンパイラ生成テーブル)。したがって、クラスを使用するすべてのモジュール (または少なくとも作成/破棄または呼び出しを行うすべてのモジュール) を再コンパイルする必要があります。クラスの仮想メソッド)。

于 2013-08-08T16:24:50.667 に答える
0

2 番目のインターフェイスが 1 番目のインターフェイスからのメソッドの完全なシグネチャを繰り返さないと仮定すると (この場合、仮想継承を使用する必要があります)、実装では 2 番目のインターフェイスは実際には 2 番目です。

ImplClass : public Interface1, Interface2

Interface1 のみを使用する既存のコードを再コンパイルする必要はありません。これは、ImplClass が 2 つの vtable への 2 つのポインターを持つようになるためですが、最初のポインターはこのクラス メモリ レイアウトの先頭に残るためです。

また、ライブラリでファクトリ メソッドを使用した場合、クライアント コードはライブラリに実装された Interface1* CreateInterface1 () メソッドのようなものを呼び出して常に Interface* を取得し (ImplClass* を直接処理することはありませんでした)、このメソッドが再コンパイルされたことを意味します。インターフェイスの順序さえ気にしません。

于 2013-08-08T16:58:38.483 に答える