成员函数指针c++

member function pointers c++

我查看了访问者模式和成员函数指针的最佳答案;但我仍然无法理解应该如何设计以下(相当简单的)场景。

在一个基本示例中,我想要一个优化器 class。给定另一个 class 的成员函数,它会找到一些最优值。像这样:

class Optimizer{
    public:
        typedef double (*Func1d)(double);
        typedef double (*Func2d)(double,double);
        void Optimize1d(Func1d* f1Ptr, double& x);
        void Optimize2d(Func2d* f2Ptr, double& x, double& y);
};

和两个示例 classes:

class A {
    double A1d(double x){return x;}
};

class B{
    double B2d(double x, double y){return x+y;}
};

和我希望能够按如下方式使用的主要功能:

void main()
{
    Optimizer opt;
    double xA_opt, xB_opt, yB_opt;
    opt.Optimize1d(&A::A1d,xA_opt);
    opt.Optimize2d(&B::B2d, xB_opt, yB_opt);
}

但是,我仍然无法让它工作。我不希望优化器直接持有指向 A 和 B 类型对象的指针;因为那时他需要熟悉这些对象。

我希望这个问题是有道理的。谢谢!

上面代码中的问题在于,在 C++ 中,pointer-to-member 函数是不同的类型,与 "regular" 函数指针不兼容。

这个类型定义

typedef double (*Func1d)(double);

在 C 和 C++ 代码中都是合法的,您可以使用 C-style "free" 这种类型的函数。

但是在你的主函数的这一行:

opt.Optimize1d(&A::A1d,xA_opt);

您正在尝试将指针作为 Func1d 传递给成员函数,但无法完成。一方面,你不能在没有指向该类型 object 的指针的情况下调用指向成员函数的指针,而且你还必须传递它。

最简单的方法是包含 header <functional> 并为此使用 std::function<double(double)>。 (假设你有 C++11,否则你可以使用 boost::function。)

您还可以按照评论中的建议执行其他操作,例如使用虚拟成员分派。 (IMO 这有点不太优雅。)

您也可以将 optimize 函数设为模板函数,并接受模板类型的 object 等等。但实际上 std::function 才是正确的选择,它会为您处理所有这些细节。

问题是 typedef double (*Func1d)(double); 不是成员函数指针,而只是一个普通的函数指针。

如果您使用真正的成员函数指针,该函数还必须有一个您说不需要的 AB 的实例。

如果您不能使 A1dB2d 静态化,则其他选项是使您的 Optimize1dOptimize2d 模板函数采用模板仿函数:

template<typename F>
void Optimize1d(F f1, double& x);
template<typename F>
void Optimize2d(F f2, double& x, double& y);

std::function:

void Optimize1d(std::function<double(double)> f1, double& x);
void Optimize2d(std::function<double(double, double)> f2, double& x, double& y);

两者都可以通过捕获 AB:

实例的 lambda 来调用
A a;
B b;
opt.Optimize1d([&a](double x){return a.A1d(x); }, xA_opt);
opt.Optimize2d([&b](double x, double y){return b.B2d(x, y); }, xB_opt, yB_opt);

编辑: 如果你没有 C++11,你可以使用 class 定义你自己的仿函数,它定义了一个 operator() 而不是 lambda。 class 必须在成员变量中存储指向 AB 实例的指针或引用:

struct A1d {
    A* a;
    A1d(A& a) : a(&a) {}
    double operator()(double x) { return a->A1d(x); }
};

然后您可以构建此 class 的实例并将其传递给模板化优化函数:

A1d a1d(a);  
opt.Optimize1d(a1d,xA_opt);

Live demo.

也许您甚至可以通过向 AB classes 仿函数添加一个 operator() 函数来使它们成为仿函数?