私は最近、私の小さなプログラムの奇妙な問題に遭遇しました。この動作の理由を理解するのを手伝っていただければ幸いです。
私の仕事は静かでシンプルです - Qt Graphics Framework を使用していくつかのオブジェクトを表示し、Box2D で体の位置を計算したいと考えています。したがって、私のクラス階層は次のようになります。
基本抽象クラス B2DObject が 1 つあります。これには、いくつかの Box2D 譜表 + 後続のいくつかの共通パラメーター (名前、いくつかのフラグなど) が含まれています。また、後継クラスで再実装される純粋仮想関数もいくつかあります。
次に、円、長方形、多角形などの基本的な形状を表すいくつかのクラスを実装します。次のようにしています。
class ExtendedPolygon : public B2DObject, public QGraphicsPolygonItem { ... };
class ExtendedCircle : public B2DObject, public QGraphicsEllipseItem { ... };
など (Qt に慣れていない方のために説明すると、QGraphics***Item は QGraphicsItem から継承されています)。
また、QGraphicsScene を継承し、その mousePressEvent を再実装しました。この関数では、QGraphicsScene::itemAt 関数 (QGraphicsItem* を返す) を使用して画面上のあるポイントに配置されたオブジェクトを要求し、それを B2DObject* に変換して、このオブジェクトから内部フィールドを取得しようとします。
void TestScene::mousePressEvent (QGraphicsSceneMouseEvent *event)
{
QGraphicsItem* item = itemAt (event->scenePos ());
if (item)
{
B2DObject* obj = reinterpret_cast < B2DObject* > (item);
QString objName = obj->Name(); // just for example,
// getting other internal fields has
// the same effect (described below)
// use retrieved field somehow (e.g. print in the screen)
}
// give the event to the ancestor
}
残念ながら、これらのクラスはまったく無関係であるため、ここでは dynamic_cast は機能しません。
次に、必要なオブジェクトを作成してシーンに追加します。
ExtendedPolygon* polygon = new ExtendedPolygon (parameters);
polygon->setName (QString ("Object 1"));
...
TestScene scene;
scene.addItem (polygon);
(Qt に慣れていない方のために、最後の関数のプロトタイプを次に示します。
void QGraphicsScene::addItem(QGraphicsItem *item);
すべてのアイテムを内部インデックスストレージに保存し、アイテムを再描画する必要があるときに QGraphicsItem::paint (...) を呼び出すだけだと思います。QGraphicsScene はこの項目に大きな変更を加えていないと思います)。
そのため、プログラムを実行して画面上の項目をクリックすると、問題が発生します。TestScene::mousePressEvent
が呼び出されます (上記のコードを参照)。
マウスのクリック位置を取得し、アイテムを見つけます。キャストは正常に動作します: デバッガー ウィンドウ (私は Qt Creator を使用しています) で、objが ExtendedPolygon を指していることがわかります (アドレスはアイテムをシーンに追加したときと同じであり、デバッガー ウィンドウではすべてのフィールドが表示されます)。しかし、フィールドを取得すると、いずれにせよガベージを受け取ります(取得しようとしているものは問題ではありません-QStringまたは他の構造へのポインター)。
まず、私の多重継承について何かアドバイスがあればお願いします。95% の場合は回避しようとしますが、ここではプログラミングの観点から非常に効果的です。クラス階層のアーキテクチャに関するあなたの見解を教えていただければ幸いです。
このレベルですべてがまったく問題ない場合、誰かがなぜそれが機能しないのかを理解できれば素晴らしいでしょう.
回避策についていくつかのアイデアがありますが、この問題を解決したいと思っています (同じエラーを繰り返さないようにするためです)。