14

C ++での仮想継承について読んでいるときに、Webサイトでこれを見つけました

多重継承を使用する場合、仮想継承を使用する必要がある場合があります。これの良い例は、標準の iostream クラス階層です。

//Note: this is a simplified description of iostream classes

class  ostream: virtual public ios { /*..*/ }
class  istream: virtual public ios { /*..*/ }

class iostream : public istream, public ostream { /*..*/ } 
//a single ios inherited

仮想メンバーから派生したクラスの数に関係なく、仮想メンバーのインスタンスが 1 つしか存在しないことを C++ はどのように保証しますか? C++ は追加レベルの間接化を使用して、通常はポインタを使用して仮想クラスにアクセスします。つまり、iostream 階層内の各オブジェクトには、ios オブジェクトの共有インスタンスへのポインターがあります。追加レベルの間接化により、パフォーマンスのオーバーヘッドがわずかに発生しますが、支払う代償はわずかです。

私は声明と混同しています:

C++ は追加レベルの間接化を使用して、通常はポインターを使用して仮想クラスにアクセスします。

誰もこれを説明できますか?

4

4 に答える 4

9

基本的に、仮想継承が使用されていない場合、基本メンバーは実際には派生クラス インスタンスの一部です。基本メンバーのメモリは各インスタンスに割り当てられ、それらにアクセスするためにそれ以上間接化する必要はありません。

class Base {
public:
    int base_member;
};

class Derived: public Base {
public:
    int derived_member;
};


Derived *d = new Derived();
int foo = d->derived_member;  // Only one indirection necessary.
int bar = d->base_member;     // Same here.
delete d;

ただし、仮想継承が機能すると、基本クラスが多重継承されたときにいくつかのコピーが作成されるのではなく、仮想基本メンバーが継承ツリー内のすべてのクラスで共有されます。あなたの例では、との両方から2 回継承iostreamされますが、メンバーの共有コピーは 1 つしか含まれていません。iosistreamostream

class Base {
public:
    // Shared by Derived from Intermediate1 and Intermediate2.
    int base_member;  
};

class Intermediate1 : virtual public Base {
};

class Intermediate2 : virtual public Base {
};

class Derived: public Intermediate1, public Intermediate2 {
public:
    int derived_member;
};

つまり、仮想ベース メンバーにアクセスするには、追加の間接的な手順が必要です。

Derived *d = new Derived();
int foo = d->derived_member;  // Only one indirection necessary.
int bar = d->base_member;     // Roughly equivalent to
                              // d->shared_Base->base_member.
delete d;
于 2011-03-03T11:12:28.927 に答える