0

我知道这是可能的,但我对 C++ 的缺乏经验限制了我。我想要做的是有一些系统,我可以update()向某些类添加方法,并让程序中的所有更新方法在每一帧都被调用。

Unity3D 用户可能对此很熟悉。Update()但是,当未确定的类中有未确定数量的方法时,程序如何知道调用每个方法。

我想这是一个在整个程序中动态调用函数的系统。

4

6 回答 6

6

没有魔杖可以为您做到这一点。您需要手动维护您创建的具有此Update方法的所有对象的列表,并在需要时迭代列表,依次调用每个对象的方法。

此外,您必须先满足编译器的要求,然后它才会允许您执行此操作。这意味着如果列表实际上是一个标准容器,例如std::vector,它需要是一个指向某个基类的容器,该基类由它内部的所有实例共享(这是标准方法)。有一些方法可以让你绕过这个限制,但在诉诸此类之前,你应该非常清楚自己在做什么。

于 2012-06-29T13:23:49.843 回答
2

您正在寻找的内容与观察者模式非常相似。您需要注册您的对象,以便在发生某些操作时调用它们的“通知”(或更新)方法。该动作可以是计时器或每个循环,这取决于您。

http://en.wikipedia.org/wiki/Observer_pattern将让您对这种设计模式有一个很好的了解。

于 2012-06-29T13:49:33.780 回答
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 回答
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)的一种有趣方式:

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() 方法更新任何一个对象。但是您也可以通过调用从父级继承的 .update_all() 方法来更新某种类型的所有对象。注意:我还没有测试过这段代码的错误,但它的要点就在那里。

于 2012-06-29T18:48:00.890 回答