我知道这是可能的,但我对C ++的经验不足限制了我。我想要做的是有一些系统,我可以向某些类添加update()
方法,并且每帧都调用程序中的所有更新方法。
Unity3D用户可能对此很熟悉。但是,如果在未确定的类中存在未确定数量的方法,程序如何知道调用每个Update()
方法。
我想这是一个在整个程序中动态调用函数的系统。
答案 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,但它的要点就在那里。