我正在尝试基于最常见答案中的链接代码实现事件管理器: Game Objects Talking To Each Other
但是当我尝试注册回调时,我收到错误。 我确定它与typedef有关,我承认我不确定它是如何工作的,但它在链接代码中的形式完全相同。 B类应该从接口继承,那么为什么类型不同? 我已经将代码浓缩成下面最小的例子。
#include <iostream>
class Interface;
typedef void (Interface::*Callback)(void *data);
class Interface
{
public:
void Register (Callback func);
};
void Interface::Register(Callback func)
{
std::cout << "Register" << std::endl;
}
class B : public Interface
{
public:
B();
void Echo(void *data);
};
B::B()
{
Register( (Callback)Echo );
}
void B::Echo(void *data)
{
std::cout << "Echo" << std::endl;
}
int main()
{
B b;
return 0;
}
这是我在g ++ 4.6.1下得到的错误:
test.cpp: In constructor ‘B::B()’:
test.cpp:31:22: error: argument of type ‘void (B::)(void*)’ does not match ‘Callback {aka void (Interface::*)(void*)}’
有谁能解释我做错了什么? 感谢
答案 0 :(得分:1)
正如@Kerrek正确指出的那样,Echo
不是Interface
的成员,因此B::Echo
不符合Interface::*Callback
的条件。但您可以使用模板来实现这一目标,例如:
template <class T> class Interface {
public:
typedef void (T::*Callback)(void *data);
void Register(Callback func) {
std::cout << "Register" << std::endl;
}
// ...
};
class B : public Interface<B> {
public:
B() {
Register(&B::Echo);
}
void Echo(void *data) {
// Do something
}
};
答案 1 :(得分:0)
我认为你最好使用std :: function(c ++ 11)或boost :: function(c ++ 03 + boost)
#include <iostream>
class Interface;
typedef void (Interface::*Callback)(void *data);
class Interface
{
public:
std::function<void(void*)> register;
Interface(std::function<void(void*)> register_)
: register(register_) //intializer list
{}
virtual ~Interface(){} //put me in
};
void Interface::Register(Callback func)
{
std::cout << "Register" << std::endl;
}
class B : public Interface
{
public:
B();
void Echo(void *data);
};
B::B()
: Interface( std::bind(B::Echo, this) )
{}
void B::Echo(void *data)
{
std::cout << "Echo" << std::endl;
}
虽然为什么你不使用纯虚拟机是我的
class Interface
{
public:
virtual void Echo(void*)=0;
};
void B::Echo(void *data) //implements Echo
{
std::cout << "Echo" << std::endl;
}
call interface-&gt; echo将调用孩子
如果您需要表现,请使用
http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
对虚空非常小心*通常认为它们很糟糕。
在评论中编辑地址点:非纯虚拟
class Interface
{
public:
virtual ~Interface(){} //put me in
virtual void echo(void*){} //if implementation is not extended it will do nothing.
//others
};
这不是Java,接口不是语言定义的东西。通过这种方式,您可以选择一个可以选择实现哪个部分的接口,如果回调与您的类无关,那么就不要实现它。
void *因各种原因而不好。来自C ++ FAQ
避免void *(将它们保存在低级函数和数据结构中 如果你真的需要它们并提供类型安全的接口,通常 模板,给您的用户)
http://www2.research.att.com/~bs/bs_faq.html
搜索“void *”
但基本上无效*绕过了C ++从中添加的所有类型安全性。 C中的一个黑客可以弥补它没有任何多态性或通用代码这一事实。