我正在尝试根据一组用户参数设置在执行期间设置的函数指针。我想让函数指针指向一个非静态成员函数,但我找不到如何做到这一点。
我见过的例子说这只能用静态成员函数来完成,或者在直接C中使用全局变量。
简化示例如下:
class CA
{
public:
CA(void) {};
~CA(void) {};
void setA(double x) {a = x; };
void setB(double x) {b = x; };
double getA(const double x) {return x*a; };
double getB(const double x) {return x*b; };
void print(double f(const double), double x) {
char cTemp[256];
sprintf_s(cTemp, "Value = %f", f(x));
std::cout << cTemp;
};
private:
double a, b;
};
实施部分是
CA cA;
cA.setA(1.0);
cA.setB(2.0);
double (*p)(const double);
if(true) {
p = &cA.getA; //'&' : illegal operation on bound member function expression
} else {
p = cA.getB; //'CA::getB': function call missing argument list; use '&CA::getB' to create a pointer to member
//'=' : cannot convert from 'double (__thiscall CA::* )(const double)' to 'double (__cdecl *)(const double)'
}
cA.print(p, 3.0);
那么如何让p指向'getA'或'getB',以便'print'仍然可以使用它。
从我所看到的,建议是使用boost或std :: bind但我没有任何经验。我希望我不需要深入了解这些,而我只是遗漏了一些东西。
编译器MSVC ++ 2008
答案 0 :(得分:14)
不要忘记成员函数接受隐式this
参数:因此,接受double
的成员函数不能与接受非成员(免费)函数的成员函数相同double
。
// OK for global functions
double (*p)(const double);
// OK for member functions
double (CA:*p)(const double);
调用的方式也不同。首先,使用成员函数,您需要一个对象来调用它们(它的地址最终将绑定到函数调用中的this
指针)。其次,如果通过指针执行调用,则需要使用.*
运算符(或->*
运算符):
p = &CA::getA;
CA cA;
(cA.*p)();
您必须更改函数print()
的定义:
#include <iostream>
void print(double (CA::*f)(const double), double x)
{
// Rather use the C++ I/O Library if you can...
std::cout << "Value = " << (this->*f)(x);
};
最后,这就是你应该重写main()
函数的方法:
int main()
{
CA cA;
cA.setA(1.0);
cA.setB(2.0);
double (CA::*p)(const double);
if (true) // Maybe use some more exciting condition :-)
{
p = &CA::getA;
}
else {
p = &CA::getB;
}
cA.print(p, 3.0);
}
答案 1 :(得分:5)
这个答案主要关注问题中提出的编译问题。我不建议将其作为解决方案来实现。
指向成员函数的指针最好用typedef
和宏来处理。
这是调用成员函数的宏:
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
来源: [33.6] How can I avoid syntax errors when calling a member function using a pointer-to-member-function?,C++ FAQ。
这样可以避免在任何希望通过指针调用成员函数时记住丑陋的(object).*(ptrToMember)
语法。
在class
中,声明一个名为typedef
的{{1}},这会使变量声明变得更加简单:
CAGetter
然后您可以非常简单地声明您的class CA
{
public:
typedef double (CA::*CAGetter)(const double x);
功能:
print()
身体也简单,清晰,简洁:
void print(CAGetter f, double x)
样本用法:
{
std::cout << "value = " << CALL_MEMBER_FN(*this, f)(x) << '\n';
}
将指向成员函数的指针传递给同一个类的实例的方法是一种设计气味(通常不会将成员变量传递给方法,这没有什么不同)。此问题中没有足够的信息来解决底层设计问题,但是这个问题可能可以通过单独的CA a;
a.setA(3.1);
a.setB(4.2);
// Using a variable...
CA::CAGetter p = &CA::getA;
a.print(p, 1);
// without a variable
a.print(&CA::getB, 1);
// Calling the functions from outside the class...
std::cout << "From outside (A): " << CALL_MEMBER_FN(a, p)(10) << std::endl;
std::cout << "From outside (B): " << CALL_MEMBER_FN(a, &CA::getB)(10) << std::endl;
方法,成员变量或继承和多态来解决。
答案 2 :(得分:0)
您可以使用指向方法的指针:
class CA
{
public:
typedef double (CA::*getter)( double );
CA(void) {};
~CA(void) {};
void setA(double x) {a = x; };
void setB(double x) {b = x; };
double getA(const double x) {return x*a; };
double getB(const double x) {return x*b; };
void print(getter f, double x) {
char cTemp[256];
sprintf(cTemp, "Value = %f", (this->*f)(x));
std::cout << cTemp;
};
private:
double a, b;
};
int main()
{
CA cA;
cA.setA(1.0);
cA.setB(2.0);
CA::getter p;
if(true) {
p = &CA::getA;
} else {
p = &CA::getB;
cA.print( p, 3.0 );
}
或者使用boost :: bind
class CA
{
public:
typedef boost::function<double( double )> getter;
CA(void) {};
~CA(void) {};
void setA(double x) {a = x; };
void setB(double x) {b = x; };
double getA(const double x) {return x*a; };
double getB(const double x) {return x*b; };
void print(getter f, double x) {
char cTemp[256];
sprintf(cTemp, "Value = %f", f(x));
std::cout << cTemp;
};
private:
double a, b;
};
int main()
{
CA cA;
cA.setA(1.0);
cA.setB(2.0);
CA::getter p;
if(true) {
p = boost::bind( &CA::getA, &cA, _1 );
} else {
p = boost::bind( &CA::getB, &cA, _1 );
}
cA.print( p, 3.0 );
}