dor*_*ron 32 c++ virtual-functions function-pointers
在C++中实现多态行为时,可以使用纯虚方法,也可以使用函数指针(或函子).例如,异步回调可以通过以下方式实现:
class Callback
{
public:
Callback();
~Callback();
void go();
protected:
virtual void doGo() = 0;
};
//Constructor and Destructor
void Callback::go()
{
doGo();
}
Run Code Online (Sandbox Code Playgroud)
因此,要在此处使用回调,您需要覆盖doGo()方法以调用您想要的任何函数
typedef void (CallbackFunction*)(void*)
class Callback
{
public:
Callback(CallbackFunction* func, void* param);
~Callback();
void go();
private:
CallbackFunction* iFunc;
void* iParam;
};
Callback::Callback(CallbackFunction* func, void* param) :
iFunc(func),
iParam(param)
{}
//Destructor
void go()
{
(*iFunc)(iParam);
}
Run Code Online (Sandbox Code Playgroud)
要在此处使用回调方法,您需要创建一个由Callback对象调用的函数指针.
[这是我(Andreas)在问题中添加的; 它不是由原始海报写的]
template <typename T>
class Callback
{
public:
Callback() {}
~Callback() {}
void go() {
T t; t();
}
};
class CallbackTest
{
public:
void operator()() { cout << "Test"; }
};
int main()
{
Callback<CallbackTest> test;
test.go();
}
Run Code Online (Sandbox Code Playgroud)
每种实施的优缺点是什么?
Adi*_*sak 13
方法1(虚函数)
方法2(带功能指针的类)
方法3(类调用T函子)
FWIW,功能指针与Functors不同.Functors(在C++中)是用于提供函数调用的类,通常是operator().
这是一个示例仿函数以及一个使用仿函数参数的模板函数:
class TFunctor
{
public:
void operator()(const char *charstring)
{
printf(charstring);
}
};
template<class T> void CallFunctor(T& functor_arg,const char *charstring)
{
functor_arg(charstring);
};
int main()
{
TFunctor foo;
CallFunctor(foo,"hello world\n");
}
Run Code Online (Sandbox Code Playgroud)
从性能角度来看,虚函数和函数指针都会导致间接函数调用(即通过寄存器),尽管虚函数在加载函数指针之前需要额外加载VFTABLE指针.使用Functors(使用非虚拟调用)作为回调是使用参数来模板函数的最高性能方法,因为它们可以内联,即使没有内联,也不会生成间接调用.
iFunc
不能为NULL,你没有使用void *iParam
等等可能是在可能的情况下做到这一点的最好方法.它将具有最佳性能,它将是类型安全的,并且它易于理解(这是STL使用的方法).
方法2的主要问题是它根本无法扩展.考虑100个函数的等价物:
class MahClass {
// 100 pointers of various types
public:
MahClass() { // set all 100 pointers }
MahClass(const MahClass& other) {
// copy all 100 function pointers
}
};
Run Code Online (Sandbox Code Playgroud)
MahClass的规模已经膨胀,构建它的时间也显着增加.但是,虚函数的类大小和构造它的时间增加了O(1)- 更不用说你,用户必须手动为所有派生类编写所有回调函数,调整指针成为一个指向派生的指针,必须指定函数指针类型和什么乱七八糟的东西.更不用说你可能会忘记一个,或者将它设置为NULL或者同样愚蠢但完全发生的事情,因为你用这种方式编写了30个类,并且像寄生黄蜂一样违反了干扰毛虫.
方法3仅在所需回调是静态可知时才可用.
这使得方法1成为需要动态方法调用时唯一可用的方法.