对于C ++而言,我已经花了数年时间使用Obj-C,并想知道如何将Obj-C中的闭包块添加到C ++类中。这是我想要做的一些伪代码:
class Slider
{
public:
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
if(myFunctionPointer != nil)
{
// show popup menu
myFunctionPointer(this);
}
}
}
FunctionPointer myFunctionPointer = nil;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider;
mySlider->functionPointer = showPopupMenu();
}
Slider *mySlider;
};
正如你所看到的,我试图让我的Slider类在不知道任何相关内容的情况下调用函数。
这不应该那么困难,但我有兴趣以最佳/正确的方式做到这一点。 Lambdas和仿函数看起来令人难以置信。也许我正在寻找别的东西。但是什么?
答案 0 :(得分:5)
当涉及将函数视为对象时,您的基本选项是:函数指针,functor / lambda,std :: function。我将假设您可以找到他们的语法,并将重点放在他们的差异上。
当不需要闭包时,应该使用函数指针。当您要调用的过程是无状态或具有全局状态,并且范围内包含所有参数时,这适用。
当您需要创建闭包时,应该使用仿函数。由于仿函数是对象,因此可以保持内部状态并在闭包内传递参数。
lambda本质上是一个仿函数,没有明确的类型名。如果lambda的捕获列表是作为functor实现的,那么它就是它的成员。请注意,您可以为函子重载operator()
,但不能为lambda重载。
functor / lambdas的问题在于它们的每个定义都有不同的类型,并且可能不适合函数签名/类成员类型。 std :: function通过接受functor / lambda / function指针并将它们转换为统一类型的std :: function来解决问题。您可以通过性能的形式为这种灵活性支付(通常很小)的价格。
答案 1 :(得分:2)
Lambda和functor是最高级的C ++主题之一。你以前最好先从一些基础知识开始,并且对C ++类的工作原理有充分的了解。
但是,既然你问过,C ++的等价物应该是这样的:
class Slider
{
public:
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
if(myFunctionPointer)
{
// show popup menu
myFunctionPointer(this);
}
}
}
std::function<void (Slider *)> myFunctionPointer=nullptr;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider;
mySlider->functionPointer = [this](Slider *)
{
showPopupMenu();
};
}
Slider *mySlider;
};
正如我所说的那样,我认为你最好先集中精力让基础知识降低,首先是在进入这些鲨鱼出没的水域之前。
只是添加一些额外的颜色:这将编译(唯一缺少的是rightClick
或ctlKeyDown
的定义),但它可能是也可能不对,取决于所涉及对象的范围和寿命。 lambda捕获std::shared_ptr
而不是this
可能有也可能没有必要,具体取决于此应用程序中的对象如何实例化。在处理这种闭包和回调之前,理解C ++对象如何工作将是必要的先决条件。
答案 2 :(得分:-1)
有不同的方法可以实现您的目标。 这是一种避免函数指针的方法。
我没有纠正其他一些明显的错误,例如调用new
而从不删除对象时产生的内存泄漏。
在这种情况下,最佳做法是使用std::unique_ptr
class Slider
{
public:
Slider(Editor& e)
: _e(e)
{ }
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
_e.showPopupMenu(this);
}
}
Editor& _e;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider(*this);
}
Slider* mySlider;
};
这是使用模板直接在构造函数中移动仿函数的另一种解决方案。
template <typename Handler>
class Slider
{
public:
Slider(Handler&& h)
: _h(std::move(h))
{ }
void onMouseDown()
{
if(rightClick or ctlKeyDown)
{
// show popup menu
_h(this);
}
}
Handler _h;
};
class Editor
{
public:
void showPopupMenu(Slider *s)
{
// build the popupMenu with information based on the slider
}
void init()
{
// create a slider and connect the popupMenu function to it
mySlider = new Slider([this](Slider* s){ showPopupMenu(s); });
}
Slider *mySlider;
};
您也可以使用std::function
代替其他答案