如何解决提供一个指向目标类要调用的成员函数的指针,而不是函数
我正在阅读很多关于函数指针、函子和回调的问题(和答案),但我仍然不清楚哪种工具适合我。
其中一些不适用于我的场景,因为我的编译器 avr-gcc v5.4.0 似乎没有 C++ 标准库(即 std::function
不可用)。
这是我的基类:
class Debouncer
{
public:
typedef uint8_t (Debouncer::*debouncer_raw_t) (void);
Debouncer() {}
void setRawFunction(Debouncer::debouncer_raw_t callback) { _raw = callback; }
private:
debouncer_raw_t _raw;
void anotherFunction()
{
uint8_t value = _raw();
// do something
}
}
在我的其他课程中:
class Inputs
{
public:
Inputs()
{
_deb.setRawFunction(myRaw);
}
private:
Debouncer _deb;
uint8_t myRaw()
{
return something;
}
}
当然这不会编译,因为 myRaw
不是静态的。
无论如何,我将尽量避免这种情况,因为它会破坏现有代码。
如果我没记错的话,很多问题似乎都是反过来问的。
相反,我只想将我的成员函数的指针传递给我的 Debouncer
类,以便它可以在需要时调用 _raw()
。
Here 我发现这个建议可以避免使用 std::
库:
#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
void userCode(Fred& fred,FredMemFn p) // Use a typedef for pointer-to-member types
{
int ans = CALL_MEMBER_FN(fred,p)('x',3.14);
// Would normally be: int ans = (fred.*p)('x',3.14);
// ...
}
但似乎相反。这里的 Fred
类是我的 Debouncer
。
我不想调用 Debouncer
成员,而是调用 caller 类的成员(即 Input::myRaw()
)。
能否请您帮我了解一下哪种工具适合完成如此简单的任务?
解决方法
如果您知道(或要求)每个使用 Debouncer
的类都有一个公共 myRaw()
函数(或者更好的 operator()
,或者实际上是其他任何函数),那么问题就简单了:
template <typename T>
class Debouncer
{
public:
Debouncer (T* t): _t(t) {}
void anotherFunction()
{
uint8_t value = _t->myRaw();
std::cout << static_cast<int>(value);
}
private:
T* _t;
};
class Inputs
{
public:
Inputs() : _deb(this)
{
// beware,if Debouncer uses its parameter in constructor (like call a method),// you cannot use initializer list
}
uint8_t myRaw()
{
return 13;
}
void foo()
{
_deb.anotherFunction();
}
private:
Debouncer<Inputs> _deb;
};
int main()
{
Inputs i;
i.foo();
}
这将是 C++ 中的首选解决方案。例如,参见标准库 <algorithm>
- 任何采用谓词或其他可调用的函数都希望使用 operator()
调用它,而不必处理指向成员函数的指针。
如果你不知道应该调用什么函数并且你真的不能对类强加任何要求,你需要存储一个指向类的指针(或引用)和一个指向成员函数的指针。注意不能连接指向不同类成员函数的指针,所以我们再次需要模板:
template <typename T,typename Func>
class Debouncer
{
public:
Debouncer (T* t,Func f): _t(t),_f(f) {}
void anotherFunction()
{
uint8_t value = (_t->*_f)(); //I get it now why isocpp asks to use macro here,the syntax is horrible
std::cout << static_cast<int>(value);
}
private:
T* _t;
Func _f;
};
class Inputs
{
public:
Inputs() : _deb(this,&Inputs::myRaw)
{
// beware,// you cannot use initializer list
}
uint8_t myRaw()
{
return 13;
}
void foo()
{
_deb.anotherFunction();
}
private:
Debouncer<Inputs,decltype(&Inputs::myRaw)> _deb; //decltype is C++11,you could also declare type like you did in your question
};
int main()
{
Inputs i;
i.foo();
}
,
创建成员函数 virtual
是一种开销相对较低的方法,可以让单个指针(指向对象)同时指向对象的数据和正确的成员函数。
class InputsBase
{
// All classes that implement myRaw() should inherit from this class
public:
virtual uint8_t myRaw() = 0;
};
class Inputs : public InputsBase
{
public:
Inputs()
{
_deb.setRawFunction(this);
}
private:
Debouncer _deb;
virtual uint8_t myRaw()
{
return something;
}
}
然后你的 Debouncer 可以简单地存储一个指向相关对象的指针。
class Debouncer
{
public:
typedef InputsBase* debouncer_raw_t;
Debouncer() {}
void setRawFunction(debouncer_raw_t callback) { _raw = callback; }
private:
debouncer_raw_t _raw;
void anotherFunction()
{
uint8_t value = _raw->myRaw();
// do something
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。