C ++调用程序中的所有update()函数

时间:2012-06-29 13:22:26

标签: c++ methods

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

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

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

6 个答案:

答案 0 :(得分:6)

没有魔杖会为你做这件事。您需要手动维护已创建的具有此Update方法的所有对象的列表,并且在需要时依次遍历列表,依次调用每个对象上的方法。

此外,您必须满足编译器的要求才能执行此操作。这意味着如果列表实际上是一个标准容器,例如std::vector,它需要是指向其中所有实例共享的某个基类的指针的容器(这是标准方法) )。有一些方法可以让你解决这个限制,但你应该有一个非常好的想法你正在做的事情之前。

答案 1 :(得分:2)

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

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

答案 2 :(得分: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);
}

答案 3 :(得分:1)

解决这个问题的唯一解决方案我可以想到的是使用像AspectC++这样的东西。当您想要做这样的事情时,面向方面编程非常有用。

答案 4 :(得分: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();
}

答案 5 :(得分:0)

使用CRTP(奇怪的重复模板模式)的一种有趣方式:

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()方法来更新某种类型的所有对象。 注意:我还没有测试过这个代码的bug,但它的要点就在那里。