3

重複の可能性:
仮想のオブジェクト サイズ

仮想継承は派生クラスのサイズを変更しますか? 次のコードを実行しました。ここでは、1 つは仮想的に継承され、もう 1 つは非仮想的に継承された 2 つの派生クラスがあります。

class A {
 public:
int a;
  virtual void a1();
};


class non_vir_der: public A{
 public:
int c;
  virtual void aa();
};


class vir_der: public virtual A{
public:
int d;
virtual void bb();
};

int main()
{
cout<<sizeof(non_vir_der)<<"\n";
cout<<sizeof(vir_der)<<"\n";
return 0;
}

出力:

12 (imo: 4(int a)+ 4(int c)+ 4(vir ptr))

16 (余分に 4 ?)

何かを見逃していないかどうかを再度確認するために、クラス内のすべての int を削除して、必要な最小限のコードを試してみました。出力は次のとおりです。

4

4

2 番目の出力は、2 つの派生クラスが同じサイズであることを示しています。最初の実行で vir_der のサイズが 16 になるのはなぜですか? なぜ 12 ではないのですか?

4

2 に答える 2

6

この動作は完全に実装固有であり、何が起こるかについての保証はありません。とは言うものの、ほとんどのコンパイラは、基本クラスの単一のコピーを配置し、派生クラスの各インスタンスに、その1つの一意のインスタンスを指すポインタをクラス本体内に格納させることによって仮想継承を実装します。そうすれば、オブジェクトをその仮想ベースにキャストすると、コンパイラーはそのオブジェクトがどこにあるかを見つけるためのコードを発行できます。32ビットシステムでは、これは、仮想継承によってオブジェクトのサイズが4バイト増加する可能性があることを意味します。

では、データメンバーがないのになぜ違いがないのでしょうか。よくわかりませんが、これは、データメンバーのない仮想基本クラスがある場合、その中に含まれるものに実際にアクセスする必要がないことをコンパイラが十分に理解できるためだと思います。したがって、オブジェクトにアクセスする方法がないため、仮想ベースへの余分なポインタを削除することで、オブジェクトを最適化できます。しかし、私はこれについて間違っている可能性があります。

お役に立てれば!

于 2012-06-15T00:22:59.410 に答える
0

基本的に、関数またはクラスの仮想を宣言すると、コンパイラは仮想をインスタンス化します

UPCAST​​ING の場合に必要なポインター。実際には、仮想ポインター テーブルが作成されます。

すべての仮想インスタンスは実際のアドレスで保存されます。したがって、継承すると

2 番目のケースの仮想クラスでは、追加の *vptr が作成されました。

2 番目のケースでは、なぜ両方のケースで 4 なのか...これは完全にコンパイラ固有のものです。

単純なロジックによると、1 番目のケースでは 1、2 番目のケースでは 4 になるはずです。

ありがとう

于 2012-06-15T04:16:03.093 に答える