私のプログラムは、動的呼び出しの状況でデータまたはオブジェクトを転送するために void* を利用する必要があるため、プリミティブ型であっても任意の型のデータを参照できます。しかし、最近、複数の基本クラスを持つクラスの場合にこれらの void* をダウンキャストするプロセスが失敗し、メモリアドレスが正しいように見えても、これらのダウンキャストされたポインターでメソッドを呼び出した後にプログラムがクラッシュすることさえあることを発見しました。「vtable」へのアクセス中にクラッシュが発生します。
そこで、小さなテスト ケースを作成しました。環境は Mac OS X の gcc 4.2 です。
class Shape {
public:
virtual int w() = 0;
virtual int h() = 0;
};
class Square : public Shape {
public:
int l;
int w() {return l;}
int h() {return l;}
};
class Decorated {
public:
int padding;
int w() {return 2*padding;}
int h() {return 2*padding;}
};
class DecoratedSquare : public Square, public Decorated {
public:
int w() {return Square::w() + Decorated::w();}
int h() {return Square::h() + Decorated::h();}
};
#include <iostream>
template <class T> T shape_cast(void *vp) {
// return dynamic_cast<T>(vp); // not possible, no pointer to class type
// return static_cast<T>(vp);
// return T(vp);
// return (T)vp;
return reinterpret_cast<T>(vp);
}
int main(int argc, char *argv[]) {
DecoratedSquare *ds = new DecoratedSquare;
ds->l = 20;
ds->padding = 5;
void *dsvp = ds;
std::cout << "Decorated (direct)" << ds->w() << "," << ds->h() << std::endl;
std::cout << "Shape " << shape_cast<Shape*>(dsvp)->w() << "," << shape_cast<Shape*>(dsvp)->h() << std::endl;
std::cout << "Square " << shape_cast<Square*>(dsvp)->w() << "," << shape_cast<Square*>(dsvp)->h() << std::endl;
std::cout << "Decorated (per void*) " << shape_cast<Decorated*>(dsvp)->w() << "," << shape_cast<Decorated*>(dsvp)->h() << std::endl;
std::cout << "DecoratedSquare " << shape_cast<DecoratedSquare*>(dsvp)->w() << "," << shape_cast<DecoratedSquare*>(dsvp)->h() << std::endl;
}
次の出力が生成されます。
Decorated (direct)30,30
Shape 30,30
Square 30,30
Decorated (per void*) 73952,73952
DecoratedSquare 30,30
ご覧のとおり、「Decorated (per void*)」の結果は完全に間違っています。また、最初の行のように 30,30 にする必要があります。
shape_cast() でどのキャスト方法を使用しても、装飾されたパーツに対して常に同じ予期しない結果が得られます。これらの void * には完全に問題があります。
私のC++の理解から、これは実際に機能するはずです。これを void* で動作させる機会はありますか? これは gcc のバグでしょうか?
ありがとう