問題タブ [virtual-inheritance]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票する
2 に答える
185 参照

c++ - 仮想継承と委任された実装

内部および外部で使用するためのAPIを開発しています。VisualStudio10の場合。

仮想基本クラスIAと派生仮想基本クラスIBがあります。私はクラスAでIAを実装し、次にBからIBの具体的な実装を導き出します。これは私の理解では古典的なダイヤモンド問題です。したがって、IAの継承を仮想にし、AのBの継承についても同じにします。しかし、警告c4250が表示されます。(warning C4250: 'B' : inherits 'A::A::AnInt' via dominance)

  • この警告は、コンパイラが私が望むことを実行していることを示すために継ぎ目がありますが、警告に不快感を覚え、#pragmaを安全に実行できることを確認したかったのですが、気づいていない問題がありました。

コード


質問の2番目の部分。消費する開発者が問題の抽象クラスを変更できないAPIを作成している場合。継承を使用したインターフェイスの設計を回避するか、先に進んで派生クラスに仮想継承を利用させる必要があります。

0 投票する
1 に答える
17606 参照

c++ - デフォルトコンストラクタが仮想継承で呼び出されるのはなぜですか?

daughter次のコードで、タイプのオブジェクトをインスタンス化すると、デフォルトのgrandmother()コンストラクターが呼び出される理由がわかりません。

grandmother(int)コンストラクターを呼び出すか(クラスコンストラクターの仕様に従うmotherため)、仮想継承のためにこのコードをまったくコンパイルしないようにする必要があると思いました。

ここで、コンパイラーgrandmotherは私の背中でデフォルトのコンストラクターを黙って呼び出しますが、私はそれを要求しませんでした。

0 投票する
1 に答える
589 参照

c++ - 仮想継承テーブルは g++ でどのように機能しますか?

仮想継承が実際にどのように機能するかをよりよく理解しようとしています (つまり、標準に従ってではなく、 のような実際の実装でg++)。実際の質問は、太字で下にあります。

そこで、継承グラフを自分で作成しました。これには、とりわけ次の単純な型があります。

(仮想継承が理にかなっているように、階層全体にC: virtual Aandもあります。)BC: B,C

インスタンスのレイアウトをダンプする関数をいくつか作成しました。vtable ポインターを取得し、最初の 6 つの 8 バイト値 (画面に収まるように任意) を出力してから、オブジェクトの実際のメモリをダンプします。これは次のようになります。

Aオブジェクトのダンプ:

Bオブジェクトのダンプと、オブジェクトが配置されている場所。これは、それぞれの位置にA多くの s を出力することで示されます。A

ご覧のとおり、のA部分は、オブジェクトの先頭からバイトBのオフセットに配置されています (これは、インスタンス化して!に dyn キャストした場合は異なる可能性があります)。16BBCB*

プログラムは実行時に の実際の位置 (オフセット) を検索する必要があるため、 (または、アライメントのために16少なくとも a )が table のどこかに表示されると予想していました。では、レイアウトは実際にどのように見えるのでしょうか。2A


編集:ダンプはdumpandを呼び出すことによって行われdumpPositionsます:

0 投票する
2 に答える
3747 参照

c++ - Virtual Inheritance and dreaded diamond

I am having a hard time with a dreaded diamond problem. For a reminder, here is the classical class hierarchy of this problem:

To solve it, the standard solution is to make C1 and C2 use virtual inheritance to inherit from B.

My problem is that B and C1 are from an SDK that I cannot modify. Example below where I cannot make SubClassB inherit virtually from Base. Classes: PureVirtualBase, Base and SubClassB are from the SDK I use. I cannot modify them. SubClassA and Leaf are my custom classes. I can change them.

In such a situation where SubClassB cannot be changed to use virtual inheritance from Base. How what should so that:

  • Leaf instance only contains one Base
  • Avoid the ambiguity when trying to access functions defined pure virtual in PureVirtualBase and implemented in Base
  • If I comment the call to f_PurevirtualBase it compiles but I have a warning that virtual base 'Base' inaccessible in 'Leaf' due to ambiguity If I uncomment this call: I get this error : request for member 'f_PureVirtualBase' is ambiguous
  • If I prefix this call by the class name (myleaf.SubClassA::f_PureVirtualBase() then it works, but something is obviously wrong as there are 2 Base contained in the Leaf Object).

Any hint?

More info to answer comments

My target architecture is slightly more complex that the sample I provided in the original question:

LeafOne : inherits from SubClassA and SubClassB(SDK)

LeafTwo : inherits from SubClassA and SubClassC(SDK)

LeafThree : inherits from SubClassA and SubClassD(SDK)

SubClassA is my own private code. It provides custom functions. It should be able to be treated like a Base instance by SDK methods. This class won't be instantiated but it is here to be able to handle LeafOne, LeafTwo and LeafThree in the same when performing some treatment.

0 投票する
5 に答える
302 参照

c++ - 姉妹継承の使用

触れることができないいくつかの(レガシー)コードが宣言すると仮定しましょう

そして、持っているとしましょう

明示的に f() を呼び出さずに、つまり代わりに A サブクラス呼び出し B::f を作成することは可能ですか?

のようなものを持つ

(コンパイラ A::f が定義されていないため、この最後のクラスは抽象であることに注意してください)

0 投票する
1 に答える
1560 参照

c++ - C ++での仮想対非仮想の多重継承

私は現在、C ++での複数の仮想/非仮想継承の概念を理解しようとしています。クラス B と C がクラス A から実質的に継承されているかどうかを正しく理解している場合、それらは一種のシングルトン オブジェクトを共有します。つまり、両方とも 1 つの共通オブジェクト A の同じフィールドにアクセスします。多重継承は、任意の B および C オブジェクトに対して個別の A オブジェクトを作成します。

上記を考慮して、誰かがとても親切で、シンプルで実用的な文脈でそれを提示しますか? そもそもなぜ多重継承なのか、次になぜ仮想/非仮想なのか?

ありがとう。

0 投票する
1 に答える
1938 参照

c++ - 仮想多重継承-最終オーバーライド

C ++のより詳細な継承メカニズムを分析しようとしているときに、次の例に出くわしました。

上記は、どういうわけか、Right :: f()をコンパイルして呼び出します。コンパイラで何が起こっているのか、共有Baseオブジェクトが1つあること、Rightがf()をオーバーライドすることを理解していることがわかりますが、実際には、Left::f()(から継承されたBase::f())とRight::f()の2つのメソッドが必要です。オーバーライドしますBase::f()。さて、Bottomによって継承されている2つの別々のメソッドがあり、どちらも同じシグネチャを持っていることに基づいて、衝突があるはずだと思います。

C ++のどの仕様の詳細がこのケースを扱っているのか、そしてそれが低レベルの観点からどのように行われているのかを誰かが説明できますか?

0 投票する
0 に答える
152 参照

c++ - これは仮想継承の良い使い方ですか?

クラスコード自体の変更を最小限に抑えて、選択したいくつかのクラスのオブジェクトの削除を追跡したいと思います。

delete演算子を(グローバルに)オーバーロードすることを検討しましたが、オーバーロードdeleteがすべてのコンパイルユニットに存在する必要があり、私の状況では面倒になる可能性があります。また、追跡対象オブジェクトの配列が作成された場合、delete[]演算子をオーバーロードする必要がありますが、残念ながら、そのオーバーロードコード内で配列の長さ、および破棄されているオブジェクトの数を知る標準的な方法はありません。演算子をオーバーロードnew[]して割り当てとその長さを追跡することもできますが、それはクリーンなソリューションのようには見えず、delete[]演算子の同じ問題に悩まされています。つまり、すべてのコンパイルユニットでアクセスできる必要があります。

そこで、ターゲットクラスを少し変更することにしました。私の考えは、「ダミー」(場合によっては複数)の継承を使用して、ターゲットクラスの監視クラスのデストラクタを「注入」することです。もちろん、ターゲットクラスは別の子の子である可能性があるため、仮想継承の仕事のように見えます。これが私がこれまでに思いついたものです。

2つの質問があります。

これは仮想継承の良い使い方ですか?このパラシフトのアドバイスとは反対に、継承ツリーの最後のリーフに仮想キーワード(anysubsubclass派生クラスがない定義を参照)を残すのは正しいですか?重要なのは、将来、下位の派生クラスをから追加するのか、たとえばベースと最後の派生クラスの間で削除するのかについては、できるだけ気にしないことです。anysubsubclassanysubclass

2番。私のコードでわかるように、ターゲットクラスの1つにオーバーロードがあるか、コピーコンストラクターoperator=がある場合、operator=またはのコピーコンストラクターtrack_deathは呼び出されません。これは、track_deathコピーできないフィールドが含まれているため問題です。その些細なコピーコンストラクタで。私の解決策は、実装者に、コピーされるオブジェクトを使用してany*class呼び出さなければならないことを伝えると、copy_info()エラーが発生しやすくなります。より良い解決策はありますか?

0 投票する
3 に答える
153 参照

c++ - 仮想継承

私が次のようなものを持っている場合

次に、Derived のオブジェクトを作成する際のコンストラクター呼び出しの順序は、

つまり、表示される順序で

しかし、それをクラス Derived に変更すると: public Base1, virtual public Base2 {}; 次に、コンストラクター呼び出しの順序は次のようになります

なぜそうなのか理解できませんか?

別の単純な疑問: Base1 を仮想的に継承する意味と目的は何でしょうか。

0 投票する
4 に答える
7258 参照

c++ - C++ でのインターフェイスの多重継承のあいまいさ

次のようにテストコードを作成しました。

このコードを書いた理由は、関数 funcBase() が DDerived のインスタンスで呼び出せるかどうかをテストするためです。このコードをコンパイルしようとすると、C++ コンパイラ (Visual Studio 2010) でコンパイル エラー メッセージが表示されました。私の意見では、このコードに問題はありません。なぜなら、それは純粋な仮想であるためfuncBase()、インターフェイスの派生クラスで関数が実装される(したがってオーバーライドされる)ことが確実だからです。DDerivedつまり、型のポインター変数は、Implementation *Implentation を派生させて function をオーバーライドするクラスのインスタンスに関連付ける必要がありますfuncBase()

私の質問は、なぜコンパイラがそのようなエラーメッセージを表示するのですか? C++ 構文がそのように定義されている理由。つまり、このケースをエラーとして扱うには? コードを実行するにはどうすればよいですか? インターフェイスの多重継承を許可したい。もちろん、「仮想パブリック」を使用するか、関数funcBase()Implementation同様に再宣言すると

その後、すべてが問題なく実行されます。

しかし、仮想継承はパフォーマンスを低下させる可能性があり、クラスの継承関係が非常に複雑な場合、再宣言は非常に面倒なので、それをしたくなくて、より便利な方法を探しています。仮想継承を使用する以外に、C++ でインターフェイスの複数の継承を有効にする方法はありますか?