1

派生クラスと基本クラスへのポインターのキャストが実際にどのように機能するかについて興味があります。次に例を示します。

struct A {};
struct B : A {};

// Boxing a pointer to an instance of B
void* p = new B();

ここで、ポインター p を介して A の可能なメンバーまたはメソッドにアクセスしたいとします。

A* a1 = (A*)p;
A* a2 = (A*)((B*)p);

どちらが正しいですか?違いはありますか?
この件に関する詳しい情報を入手できる場所を教えてください。

4

1 に答える 1

2

この場合、実際には違いはありません。

ただし、複数の継承がある場合は違いがある可能性があります。

#include <cstdio>

struct A { int x; };
struct B { int y; };

struct C : B, A {};

int main() {
    void* c = new C();
    printf("%p\n", c);             // 0x1000
    printf("%p\n", (A*) c);        // 0x1000
    printf("%p\n", (A*) ((C*) c)); // 0x1004
    return 0;
}

または、サブクラスには仮想メソッドがありますが、親には[1]ありません。これには、仮想継承[2]の使用が含まれます。

標準に関しては、OP は C スタイルのキャストを使用するため、この場合は と同等static_castです。

キャスト シーケンスB*void*B*A*は有効です。最初の 2 つのキャストは、§5.2.9[expr.static.cast]/13 で要求されるのと同じポインターを返し、最後のキャストはポインター変換 §4.10[conv として機能します。 .ptr]/3.

ただし、キャスト シーケンスB*void*A*は実際には未定義の結果を返します。これは、結果が §5.2.9/13 で定義されていないためです ☺。


[1] :

#include <cstdio>

struct A { int x; };
struct C : A { virtual void g() {} };

int main() {
    void* c = new C();
    printf("%p\n", c);              // 0x1000
    printf("%p\n", (A*) c);         // 0x1000
    printf("%p\n", (A*) ((C*) c));  // 0x1008
    return 0;
}

[2] :

#include <cstdio>

struct A { int x; };
struct C : virtual A {};

int main() {
    void* c = new C();
    printf("%p\n", c);              // 0x1000
    printf("%p\n", (A*) c);         // 0x1000
    printf("%p\n", (A*) ((C*) c));  // 0x1008
    return 0;
}
于 2012-08-12T12:43:02.293 に答える