3

私は最近、私の小さなプログラムの奇妙な問題に遭遇しました。この動作の理由を理解するのを手伝っていただければ幸いです。

私の仕事は静かでシンプルです - 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% の場合は回避しようとしますが、ここではプログラミングの観点から非常に効果的です。クラス階層のアーキテクチャに関するあなたの見解を教えていただければ幸いです。

このレベルですべてがまったく問題ない場合、誰かがなぜそれが機能しないのかを理解できれば素晴らしいでしょう.

回避策についていくつかのアイデアがありますが、この問題を解決したいと思っています (同じエラーを繰り返さないようにするためです)。

4

2 に答える 2

1

問題の根本原因を見つけたようです。多重継承がデータ層で実際にどのように機能するかについての知識が不足していました。

A と B の 2 つの基本クラスがあるとします。それぞれがいくつかの内部データ フィールドといくつかのインターフェイスを提供します。

次に、A と B の両方を継承する派生クラス AABB を作成します。

class AABB : public A, public B {...}

AABB はいくつかの追加データ フィールドを追加し、いくつかのインターフェイスを再実装できますが、必須ではありません。

クラス AABB のオブジェクトを作成しましょう:

AABB* obj = new AABB ();

たとえば、objはアドレス 0x8416e0 を指します。このアドレスで、先祖クラス A からのデータが開始されます。先祖クラス B からのデータは、たとえば 0x841700 などのオフセット (bw は sizeof (A) に等しい必要があります) で始まります。

関数f (B* b)があり、その関数に AABB オブジェクトのポインターを渡す場合 (このように:上記f (obj)objが作成されます)、実際にはobjの開始アドレスではなく、AABB の B データ セクションの開始点のポインターが渡されます。物体。

したがって、複数の継承の内部動作に関するこの誤解は、私が抱えている問題につながりました。

于 2012-11-20T09:05:31.803 に答える
0

Qobjects と多重継承は既に処理されていると思います。例として: QObject Multiple Inheritance

于 2012-11-19T10:57:42.020 に答える