0

取り組んでいる問題があります。このパターンで互いに継承する数値クラスがあります。

#include <stdio.h>
#include <stdlib.h>

#include <list>

class TimeObject
{
  public:
    virtual void Tick()=0;

    std::list<TimeObject*> ticks;
};

class MapObject : public TimeObject
{
  public:
    MapObject()
    {
        ticks.push_front(this);

        printf("Create MapObject %p\n", this);
    }

    void Tick() { printf("mapobject tick\n"); }
};

class ControlObject : public MapObject
{
  public:
    ControlObject()
    {
        ticks.push_front(this);

        printf("Create ControlObject %p\n", this);
    }

    void Tick() { printf("controlobject tick\n"); }
};

int main()
{
    ControlObject test;

    std::list<TimeObject*>::iterator it = test.ticks.begin();

    for(; it != test.ticks.end(); it++)
    {
        TimeObject *trigger = *it;

        trigger->Tick();
    }

    return 0;
}

この例のリストには、TimeObject派生クラスが格納されています。私の問題は、ディスパッチMapObjectでもあるリストにポインターを格納すると、ControlObjects常にControlObject関数が選択されることです。

ポリモーフィズムを使用してポインターでMapObject関数をトリガーすることは可能ですか? ControlObjectそれが不可能/実用的でない場合、良い代替手段は何ですか?

4

3 に答える 3

2

List( ) には常にBase クラスへのポインタを格納する必要があります。ポインターは、コンテナーにポインターを追加する前 、型のオブジェクトを指すように正しく作成する必要があります。これを行うと、実際のオブジェクトの種類に応じて 、動的ディスパッチが適切な関数を呼び出します。何もする必要はありません。 A*std::list< A*>
BC

なぜあなたがそうでないデザインを持ちたいのかわかりません。そうする正当な理由があれば教えてください.

ControlObject::tick()コードで常に呼び出すのはなぜですか?
電話すると:

ticks.push_front(this); 

ControlObject::ControlObject()基本的に、リストに追加した最初のポインターを上書きすることになります。最初にプッシュされたポインターのタイプは、ポインターを後ろに変更したため、もうありません。ポインターの所有権をリストに譲渡しませんでしたが、MapObject *両方ControlObject *所有権を共有していて、派生クラスのコンストラクター呼び出しを介してリスト内のオブジェクトを変更しました。これによりControlObject *、動的ディスパッチが正しいメソッドを正しく決定して呼び出すリストに 2 つのオブジェクトが残ります。

動的ディスパッチの動作に問題はありません。これは正しい動作です。
呼び出したい場合MapObject::Tick();は、明示的にコンパイラにそうするように指示する必要があります。動的ディスパッチはオブジェクトの実際のタイプで機能し、正しく機能しています。

void controlobject::Tick() 
{ 
    printf("controlobject tick\n"); 
    MapObject::Tick();
}

コメントからの複製:

残念ながら、これは悪い設計です。コードは正常に機能し、C++ 標準で定義されているように機能します。問題は設計にあります。より広い意味で達成しようとしていることの詳細を提供しない限り、新しいデザインについて推測するのは難しく、むしろ無意味です。

于 2012-05-23T05:05:04.260 に答える
0

MapObject::Tick()現在の例では、内部を呼び出すことで、両方の仮想メンバー (または基になる型に応じて 1 つだけ) を呼び出すことができるはずですControlObject::Tick()

class ControlObject : public MapObject
{
  public:
    ControlObject()
    {
        ticks.push_front(this);

        printf("Create ControlObject %p\n", this);
    }

    void Tick() { printf("controlobject tick\n"); MapObject::Tick(); }
};

明示的な関数呼び出し表記が必要です。

于 2012-05-23T05:57:43.497 に答える