在这个问题中,假设我们已经以一种漂亮,谨慎的方式处理了所有指针 - 为了防止问题膨胀,我不想在这里包含我的清理代码!
假设我们有两个类Foo
和Bar
,其类定义如下:
class Foo
{
public:
Foo();
void fooFn();
};
class Bar
{
public:
Bar();
void barFn();
};
假设Foo
和Bar
有必要没有继承关系,但我们需要调用fooFn
和barFn
来响应某些刺激。我们可以创建一个带有容器的控制器类,可以在fooFn
和barFn
的特定实例上调用Foo
和Bar
- 例如静态std::vector
- 但是我们遇到了一个问题:指向Foo
和Bar
实例的成员函数的指针属于不同的类型。
通过在控制器类中使用静态vector< std::function<void()>* >
,我们可以进行解决方法。 Foo
和Bar
个实例可以有一个函数,通过一个捕获this
的lambda函数为向量添加指针:
void Foo::registerFnPointer()
{
ControllerClass::function_vector.push_back( new [this](){ return this->fooFn(); } );
}
我已经测试了这种方法,它似乎没有任何问题。也就是说,我担心可以通过规避之前提到的类型差异引起的问题......我是否担心什么?有没有更好的方法来实现同等功能?
答案 0 :(得分:1)
我看到的唯一问题实际上与仿函数无关,而是与对象生命周期有关。那就是:我不确定你是如何确保每当Foo或Bar实例被销毁时你总是取消注册用ControllerClass注册的仿函数。
但是,你提到你做了适当的内存管理。
在我看来,您不需要存储指向function<void()>
的指针,您只需将函数存储为值(即vector<function<void()>>
)。
在C ++ 11和lambdas之前,为了达到相同的效果你也会使用(boost)函数,但是你会使用boost :: bind和fooFn的地址以及绑定到的第一个参数指向Foo对象实例的指针(或引用)。
这将创建一个函数实例,该实例包含在给定对象上调用fooFn方法所需的所有信息。然后,您可以将实例存储在向量中以便稍后调用它(并且确保没有绑定到已销毁对象的boost::function
仍然注册的问题同样存在)
编辑:
为了完整起见,指向绑定成员的Boost绑定文档的链接:http://www.boost.org/doc/libs/1_56_0/libs/bind/bind.html#with_member_pointers
你正在做的事情实际上非常相似,只是你现在使用lambda捕获对象指针并定义要调用的函数。
所以我认为你正在做的事情没有问题(除了我已经提到的那个)。
答案 1 :(得分:-1)
您可以使用适配器类。对于你正在做的事情,这可能有点过头了,但它可能有效。
这样做的好处是:
您不必更改原始课程。创建void Foo::registerFnPointer()
很难看。
您不必使用静态std::vector
。
您不必处理函数指针。
所以,让我们说你有两个不同的类:
struct Foo
{
void fooFn () {
std::cout << "Foo::fooFn ()" "\n" ;
}
};
struct Bar
{
void barFn () {
std::cout << "Bar::barFn ()" "\n" ;
}
};
目标是将它们放入容器并调用各自的*Fn ()
成员函数。
适配器看起来像这样:
struct Adapter_Base
{
virtual ~Adapter_Base () {} ;
virtual void adapterFn () = 0 ;
};
template <typename T>
struct Adapter : Adapter_Base
{
T tVal ;
Adapter (const T &tVal) : tVal (tVal) {}
void adapterFn () ;
};
template <>
void Adapter <Foo>::adapterFn ()
{
tVal.fooFn () ;
}
template <>
void Adapter <Bar>::adapterFn ()
{
tVal.barFn () ;
}
你可以像这样使用它:
int main ()
{
std::vector <std::unique_ptr <Adapter_Base> > v1 ;
std::unique_ptr <Adapter_Base> u1 (new Adapter <Foo> (Foo ())) ;
std::unique_ptr <Adapter_Base> u2 (new Adapter <Bar> (Bar ())) ;
v1.push_back (std::move (u1)) ;
v1.push_back (std::move (u2)) ;
for (auto &adapter : v1) {
adapter->adapterFn () ;
}
return 0 ;
}