2005-10-02
Cでは、ある型へのポインタから別の型へのポインタにキャストした場合でも、ポインタの値(アドレス)が変わることはありませんでした。Cプログラマにとって、特にアドレスを意識することが多い組み込みプログラマにとっては、これはある意味で大原則のひとつかもしれません。
しかし、C++では、Cのそうした大原則・常識も簡単に覆ってしまいます。C++では、キャスト前の型とキャスト後の型の間に継承関係があれば、ポインタの値(アドレス)が維持されるとは限らないのです。
例えば、あるクラスAから派生したクラスBがあるとします。下の例を見てください。
class A
{
public:
void foo();
private:
int x;
};
class B : public A
{
public:
void bar();
private:
int y;
};
このとき、クラスBのオブジェクトは、クラスA相当の部分オブジェクトを内在することになります。ところが、そのクラスA相当分は、クラスBのデータメンバであるB::yより前に配置されるか、後に配置されるかは処理系に依存します。
もし、クラスA相当の部分オブジェクトよりB::yの方が先(アドレスが下位)に配置されたとすれば、クラスBからクラスAにキャストする場合には、sizeof(B::y)の分(および場合によってはパディングの分)だけ、アドレスをずらさなければなりません。クラスAからクラスBにキャストする場合も同様です。
現実には、クラスAの部分オブジェクトの方がB::yより先に配置されることが多いようですが、これを期待した実装はすべきではありません。
また、キャストによって確実にポインタの値がずれる場合もあります。それは多重継承の場合です。多重継承では基底クラスが複数あるわけですから、どの基底クラスに相当するの部分オブジェクトが先に配置されたところで、それ以外の基底クラスへのポインタにキャストされれば、必ずポインタの値がずれることになります。
Comment