6

Codeproject の Don Clugstonの記事を読んでいました。美品でかなり有名です。次のコード スニペットでは、理解するのが非常に難しい特定の概念が見つかりました。

class A {
 public:
       virtual int Afunc() { return 2; };
};

class B {
 public: 
      int Bfunc() { return 3; };
};

// C is a single inheritance class, derives only from A
class C: public A {
 public: 
     int Cfunc() { return 4; };
};

// D uses multiple inheritance
class D: public A, public B {
 public: 
    int Dfunc() { return 5; };
};

スニペットの後には、次の段落が続きます。

クラス C のメンバー関数ポインターを作成するとします。この例では、Afunc と Cfunc はどちらも C のメンバー関数であるため、メンバー関数ポインターは Afunc または Cfunc を指すことができます。しかし、Afunc には C::A を指す this ポインター (これを Athis と呼びます) が必要ですが、Cfunc には C を指す this ポインター (これを Cthis と呼びます) が必要です。コンパイラの作成者は、この状況にトリックで対処します。つまり、A が C の先頭に物理的に格納されるようにします。これは、Athis == Cthis を意味します。心配する必要があるのは 1 つだけです。世界は順調です。

私が理解したい唯一のことは、上記の段落の BOLD と ITALICS の行です。

Afunc には C::A へのポインターが必要であるのに対し、Cfuncには C へのポインターが必要であることは完全には理解できません。

どんな助けでも大歓迎です。

4

1 に答える 1

9

C ++でメンバー関数を呼び出すことにより、内部で発生するのは、インスタンスが非表示の最初の引数として渡されることです(ただし、この動作は厳密に実装定義の動作であることに注意してください。C++標準はこのトピックについて何も言うことはなく、単なるそれを実装する非常に一般的な方法):

x.f(y); // is treated internally as:
f(&x, y);

thisこの最初の引数は、ポインタを介して利用できます。

ここで、Afunc上記の例では、内部署名void Afunc(A* const this)CFuncあり、内部署名がありますvoid CFunc(C* const this)

どちらの場合も引数の型が異なるため、同じオブジェクトで関数を呼び出す場合は、別のポインタを渡す必要があることに注意してください。C ++は、派生オブジェクトからそのベースオブジェクトへの暗黙的な変換を定義することでこれを解決します。つまり、次のコードでは次のようになります。

C* pc = something;
pc->Afunc();

このコードは、内部的に次のように扱われます(擬似コード)。

C* pc = something;
Afunc(static_cast<A*>(pc));

このキャストは、単一継承の場合、引用で言及されているトリックによる操作なし(つまり、削除することができます)です。Cオブジェクトとその親Aオブジェクトは同じ物理アドレスに格納されます。Cメモリ内のアドレスに格納されているタイプのオブジェクトはx、そのタイプの親オブジェクトアドレスに格納され、その後に存在する可能性のある他のすべてのメンバーが続くように物理的に配置されます(ただし、あなたの場合はメンバーなし、および)。AxCsizeof(C) == sizeof(A)

于 2012-06-12T09:30:22.263 に答える