以下のようなクラスを定義して各基本クラスへのポインタにキャストした時のアドレスが
ずれてしまいました。いろいろ試してみて[class C]の基本クラスのを指定する順番を
変えた時に、後ろ側のクラス型にキャストした時に発生することが解りました。
自分としてはクラスAもBも基本クラスなので問題なくキャスト出来るものだと思っていました。
何故こうなるのかご教授願います。
以下が実行結果と実際のコードです。
//---実行結果---
&d = 12feec
pA = 12feec
pB = 12fef4
pC = 12feec
//--------------
#include <stdio.h>
class A
{
public:
int a;
A(){}
virtual ~A(){}
};
class B
{
public:
int b;
B(){}
virtual ~B(){}
};
class C : public A,public B
{
public:
int c;
C(){}
virtual ~C(){}
};
class D : public C
{
public:
int d;
D(){}
virtual ~D(){}
};
void main()
{
D d;
A* pA = &d;
B* pB = &d;
C* pC = &d;
char str[128];
sprintf(str,&d = %x\npA = %x\npB = %x\npC = %x\n,&d,pA,pB,pC);
printf(str);
}
ストラウストラップのThe Annotated C++ Reference Manual
(註解 C++リファレンスマニュアル)の 10.3c あたりが参考になると思います。
多重継承の場合、キャストはポインタの値を変更し得ます。
この例でいくと C のインスタンスのメモリ割り当ての内部のどこかに
A 部分と B の部分がそれぞれ別々に出来上がります。
そしてキャストを行った場合 A の部分の先頭、B の部分の先頭を
それぞれ指します。
|<----------------- D -------------------------------->|
|<--- A --->|<--- B --->|<-- Cの残り-->|<-- Dの残り -->|
↑ココ ↑ココ
// 多重継承時の基底クラスのメンバの配置順は既定されていないので
// 必ずこのようになるとは限りませんが。
なるほど、そうだったのですか。
ポインタの値が変化することを知らなかったので、
かなり無茶なことをしていたようです。
明示的にキャストしたアドレスを使用するようにしたら
うまくいくようになりました。
わざわざ明示的にキャストせずとも,問題なく動きますよ。
#明示的にreinterpret_castすると問題になりますが……。
継承関係がある型のポインタ間で明示的なキャストが必要になるのは,
・dynamic_castを必要とする場合
・ダウンキャストにおけるstatic_cast
・protected/private継承を無視するためのC-likeキャスト
くらいだと思います。