これはthis section on learncpp.comを読んでいるときに遭遇した質問です。私はここに記載されているコードを使用し、テストのために少し変更を加えました。C++での仮想継承中にコンストラクタを呼び出す
背景
仮想継承は、二つの効果を有する基底クラスに共通の基準を作成します。
最初に、基底のメンバーのコピーが作成されると(例えば、PoweredDeviceにprint()関数を追加し、main()でそれを呼び出すとコンパイラエラーが発生する)ので、あいまいさは取り除かれます。
第2に、最も派生したクラスは、基本コンストラクタの呼び出しになります。中間クラスの1つが初期化リストで基本コンストラクタを呼び出そうとすると、呼び出しはignoredになるはずです。
問題
私がコンパイルしたコードを実行し、それが返されます。
PoweredDevice: 3
PoweredDevice: 3
Scanner: 1
PoweredDevice: 3
Printer: 2
それは返す必要があります:
PoweredDevice: 3
Scanner: 1
Printer: 2
私はGDBを使用して、実行を追跡する場合(7.11 .1)、中間関数も初期化リストを介してPoweredDeviceを呼び出していることを示していますが、これらは無視する必要があります。 PoweredDeviceを複数回初期化してもメンバーのあいまいさはありませんが、コードは一度しか実行されない場合に複数回実行されるため、問題があります。より複雑な問題については、私は仮想継承を使用するのが快適ではないでしょう。
なぜこれらの中間クラスはまだベースを初期化していますか?それは私のコンパイラ(gcc 5.4.0)の奇妙なものですか、あるいは私は仮想継承の仕組みを誤解していますか?
編集:コード
#include <iostream>
using namespace std;
class PoweredDevice
{
public:
int m_nPower;
public:
PoweredDevice(int nPower)
:m_nPower {nPower}
{
cout << "PoweredDevice: "<<nPower<<endl;
}
void print() { cout<<"Print m_nPower: "<<m_nPower<<endl; }
};
class Scanner : public virtual PoweredDevice
{
public:
Scanner(int nScanner, int nPower)
: PoweredDevice(nPower)
{
cout<<"Scanner: "<<nScanner<<endl;
}
};
class Printer : public virtual PoweredDevice
{
public:
Printer(int nPrinter, int nPower)
: PoweredDevice(nPower)
{
cout<<"Printer: "<<nPrinter<<endl;
}
};
class Copier : public Scanner, public Printer
{
public:
Copier(int nScanner, int nPrinter, int nPower)
:Scanner {nScanner, nPower}, Printer {nPrinter, nPower}, PoweredDevice {nPower}
{ }
};
int main()
{
Copier cCopier {1,2,3};
cCopier.print();
cout<<cCopier.m_nPower<<'\n';
return 0;
}
どのような「わずかな変更」をしましたか?とにかくここにコードを投稿してください – user463035818
ようこそスタックオーバーフロー! ** [編集] **あなたの質問は[mcve]または[SSCCE(ショート、自己完結型、正しい例)](http://sscce.org) – NathanOliver
編集にコードを追加しました。バリエーションは、異なるアクセス指定子を含む基本クラスのメンバ値と関数を調べました。私はまた、仮想継承アクセスレベルの変更を試みました。 –