提问人:MWRazer 提问时间:8/29/2023 最后编辑:MWRazer 更新时间:8/29/2023 访问量:100
将函数作为类的属性 - C++
Having a function as a property on a class - C++
问:
我希望在 C++ 中创建一个类,它可以将可更改的功能作为其单个属性之一。有没有标准方法可以实现这一点?语法会是什么样子?
例如,我尝试并想做的事情:
#include <iostream>
class Thing {
private:
int val;
void func();
public:
Thing(int val = 0) {
this->val = val;
}
void setFunc(void func()) { this->func() = func; }
void useFunc() { this->func(); }
};
int main() {
Thing thing1 = Thing(1);
thing1.setFunc({
std::cout << "i am thing 1, my value is: " << this->val;
});
thing1.useFunc();
return 0;
}
我不确定这样的事情的语法会是什么样子,或者是否需要指针。这(可能很明显)返回了几个错误,它们是:
./main.cpp:16:46: error: expression is not assignable
void setFunc(void func()) { this->func() = func; }
~~~~~~~~~~~~ ^
./main.cpp:28:51: error: invalid use of 'this' outside of a non-static member function
std::cout << "i am thing 1, my value is: " << this->val;
^
我意识到我可以使用很多不是函数的属性,然后有一种方法使用这些属性来确定结果,但是我不想这样做,因为它需要更多的属性,我想尝试一些不同的东西来学习如何做到这一点。在这个例子中,做我想做的事情是没有意义的,但这只是一个例子。
答:
1赞
user4581301
8/29/2023
#1
第 1 步:定义函数指针!
class Thing {
private:
int val;
// void func(); declares a function that will be defined later
// not what we want.
using func_ptr = void (*)(); // define a new type. It make everything
// that follows much easier
func_ptr func; // declares func to be a pointer to a function
public:
Thing(int val = 0): val(val) // use member initializer list
// all members must be initialized
// before entering the body of the
// constructor. not that important
// for an int, but very important for
// types with expensive initialization
// or no default initialization
{
}
void setFunc(func_ptr func) // pass a function pointer
{
this->func = func; // Do not call the function!
// avoid reusing names in the same scope.
// It only leads to trouble
}
void useFunc()
{
func(); // which func is not ambiguous here. No need for this
}
};
第 2 步:分配函数!
thing1.setFunc({
std::cout << "i am thing 1, my value is: " << this->val;
});
看起来您正在尝试使用 Lambda 表达式。这里有几个问题。
- 语法错误。C++不是一种奖励猜测的语言。买一两本好书,以可控的方式学习语法。另一种选择是缓慢的、痛苦的、不值得做的。
正确的语法如下所示
thing1.setFunc([](){
std::cout << "i am thing 1, my value is: " << this->val;
});
- 不幸的是,Lambda 没有线索表明它与 关联,也不是 的成员,因此它不能使用 。这有点令人费解。Lambda 需要 Capture ,但一旦捕获,就不能再使用函数指针。它们太简单了,无法处理捕获。输入
std::function
。thing1
Thing
this
thing1
第 3 步:重新开始std::function
#include <iostream>
#include <functional>
class Thing {
private:
int val;
using func_ptr = std::function<void ()>;
func_ptr func;
public:
Thing(int val = 0): val(val)
{
}
void setFunc(func_ptr func)
{
this->func = func;
}
void useFunc()
{
func();
}
int get_val()
{
return val;
}
};
int main() {
Thing thing1 = Thing(1);
thing1.setFunc([thing1](){ // captures by value. Not always what you
// want, but generally the safest option.
// Just fine for a simple example like this
std::cout << "i am thing 1, my value is: " << thing1.val;
});
thing1.useFunc();
return 0;
}
这仍然无法工作,因为是私人成员,无法从外部或朋友访问。Lambda 两者都不是,也不容易被塑造成一个。要么 A) Lambda 必须调用一个成员函数来完成实际工作,这毫无意义,因为你会丢弃所有这些 rigamarole,而只是直接调用成员函数,B) 你添加一个 getter for,Lambda 使用 getter,或者 C) 你做 .Thing::val
Thing
Thing
Thing
Thing::val
Thing::val
public
B 看起来是最好的选择。但是,如果您需要的逻辑必须改变怎么办?这需要...thing1
第 4 步:为总体问题找到一个更简单的答案。
评论
1赞
paddy
8/29/2023
如果函数应始终在调用它的对象的上下文中执行,那么它可能应该接受一个参数,而不是在 lambda 中捕获对象(通过引用,或在您的示例中通过复制)。Thing&
0赞
user4581301
8/29/2023
好点子。使切线变成 std::function
有点毫无意义。
0赞
paddy
8/29/2023
我不会说这一定是毫无意义的。Lambda 仍然可以捕获其他值,使它们比直接函数更通用。虽然很难从原来的问题中知道整个设计是否是XY问题。
评论
std::function
setFunc
Thing
this->val
std::function