0

これが可能であることはわかっていますが、C++ の経験が浅いため制限があります。私がやりたいのはupdate()、特定のクラスにメソッドを追加し、プログラム内のすべての更新メソッドをフレームごとに呼び出すことができるシステムを用意することです。

Unity3D ユーザーはこれに精通しているかもしれません。Update()しかし、未定のクラスに未定の量のメソッドがある場合、プログラムはどのようにしてすべてのメソッドを呼び出すことを知るのでしょうか。

プログラム全体で動的に関数を呼び出すシステムだと思います。

4

6 に答える 6

6

あなたのためにこれを行う魔法の杖はありません。このメソッドを持つ、作成したすべてのオブジェクトのリストを手動で維持する必要がありUpdate、必要に応じて、各オブジェクトのメソッドを順番に呼び出してリストを反復処理します。

さらに、これを行う前に、コンパイラの要件を満たす必要があります。これは、リストが実際に などの標準コンテナである場合、リスト内のすべてのstd::vectorインスタンスによって共有される基本クラスへのポインタのコンテナである必要があることを意味します (これが標準的なアプローチです)。この制限を回避するためのアプローチはいくつかありますが、そのような手段に頼る前に、自分が何をしているのかについて非常によく考えておく必要があります。

于 2012-06-29T13:23:49.843 に答える
2

概念実証のためにこれをここに置きました。から継承する場合Updateable: メインループから呼び出しUpdateModule::Update(delta_time);て、構築されたクラスを更新できます。

ループされたリンク リストを使用して、更新する項目を追跡します。これにより、動的なメモリ割り当てが不要になります。UpdateModule はトリックを使用して、静的に作成されたオブジェクトでも機能することを確認します。

class Updatable
{
    friend class UpdateModule;
public:
    virtual void Update(float delta_time) = 0;
protected:
    Updatable();
    virtual ~Updatable();
private:
    Updatable* m_next;
    Updatable* m_prev;
};


class UpdateModule
{
    friend class Updatable;
public:
    static void Update(float delta_time)
    {
        Updatable* head = *GetHead();
        Updatable* current = head;
        if (current)
        {
            do
            {
                current->Update(delta_time);
                current = current->m_next;
            } while( current != head);
        }
    }
private:

    static void AddUpdater(Updatable* updatable)
    {
        Updatable** s_head = GetHead();
        if (!*s_head)
        {
            updatable->m_next = updatable;
            updatable->m_prev = updatable;
        }
        else
        {
            (*s_head)->m_prev->m_next = updatable;
            updatable->m_prev = (*s_head)->m_prev;
            (*s_head)->m_prev = updatable;
            updatable->m_next = (*s_head);
        }
        *s_head = updatable;    
    }

    static void RemoveUpdater(Updatable* updatable)
    {
        Updatable** s_head = GetHead();
        *s_head = updatable->m_next;
        if (*s_head != updatable)
        {
            updatable->m_prev->m_next = updatable->m_next;
            updatable->m_next->m_prev = updatable->m_prev;
        }
        else
        {
            *s_head = NULL;
        }
        updatable->m_next = NULL;
        updatable->m_prev = NULL;
    }
private:
    static Updatable** GetHead()
    {
        static Updatable* head = NULL;
        return &head;
    }
};


Updatable::Updatable() : m_next(NULL), m_prev(NULL)
{
    UpdateModule::AddUpdater(this);
}

Updatable::~Updatable()
{
    UpdateModule::RemoveUpdater(this);
}

使用例:

class SomeClass : private Updatable
{
public:
    virtual void Update(float)
    {
        printf("update for SomeClass was called\n");
    }
};

class AnotherClass : private Updatable
{
public:
    virtual void Update(float)
    {
        printf("update for AnotherClass was called\n");
    }
};

int main()
{
    SomeClass a, b;
    AnotherClass c, d;
    UpdateModule::Update(0);
}
于 2012-06-29T16:19:02.840 に答える
2

探しているものは、オブザーバー パターンに非常に似ています。アクションが発生したときにオブジェクトの「通知」(または更新) メソッドが呼び出されるようにするには、オブジェクトを登録する必要があります。そのアクションは、タイマーまたはすべてのループにすることができます。それはあなた次第です。

http://en.wikipedia.org/wiki/Observer_patternは、この設計パターンの概要を説明します。

于 2012-06-29T13:49:33.780 に答える
1

私が考えることができるこれを解決するための唯一の解決策は、のようなものを使用することですAspectC++。アスペクト指向プログラミングは、このようなことをしたいときに非常に便利です。

于 2012-06-29T13:30:57.000 に答える
1

この Update メソッドを持つすべてのクラスを抽象クラスから派生させてから、このメソッドを呼び出したいすべての変数へのポインターを何らかのベクターで配置します。

初歩的な例を次に示します。

class Updatable
{
public:
    virtual void update() = 0;
};

class SomeClass : public Updatable
{
public:
    virtual void update()
    {
        printf("update for SomeClass was called\n");
    }
};

class AnotherClass : public Updatable
{
public:
    virtual void update()
    {
        printf("update for AnotherClass was called\n");
    }
};

int main()
{
    Updatable* v[10];
    int n = 0;
    SomeClass a, b;
    AnotherClass c, d;
    v[n++] = &a;
    v[n++] = &b;
    v[n++] = &c;
    v[n++] = &d;

    for (int i = 0; i < n; i++)
        v[i]->update();
}
于 2012-06-29T13:57:44.800 に答える
0

CRTP (Curiously Recurring Template Pattern) を使用した楽しい方法の 1 つ:

template <class T> struct updatable
{
    static std::set<updatable*> objects;

    updatable()
    {
        objects.insert(this);
    }

    ~updatable()
    {
        objects.erase(this);
    }

    void update_all()
    {
        for (auto& o : objects)
            static_cast<T* const>(o)->update();
    }
};

template <class T>
std::set<updatable<T>*> updatable<T>::objects = {};

struct Some_object : updatable<Some_object>
{
    void update()
    {
        // logic here.
    }
};

.update() メソッドを使用して、任意の 1 つのオブジェクトを更新できるようになりました。ただし、親から継承された .update_all() メソッドを呼び出すことで、特定のタイプのすべてのオブジェクトを更新することもできます。注: このコードのバグはまだテストしていませんが、要点はそこにあります。

于 2012-06-29T18:48:00.890 に答える