【问题标题】:passing a pointer to a class method as a function argument [duplicate]将指向类方法的指针作为函数参数传递[重复]
【发布时间】:2013-12-23 14:04:22
【问题描述】:

我有课

class A{
    A(/*constructor arguments*/);
    double MethA(double);
};

我想在一个函数中传递MethA 方法,该函数需要一个指向函数的指针:

double function(double (*f)(double), double x){
    return f(x);
}

所以我要做的就是打电话

A a(/*constructor arguments*/);
function(a.MethA,1.0);

但它不能编译。

我很确定这个问题在其他地方得到了回答,但我找不到在哪里,因为我不确定我使用的术语是否正确。我是否试图将类方法上的指针作为函数参数传递?或者,将函数指针作为类的成员传递......我很困惑:-(

【问题讨论】:

  • 请正确拼写。 class 是小写字母,最后需要一个分号。细节,但编程就是细节。
  • 为什么写代码充其量是不可理解的?你有虚函数。传入具有其中之一的对象并使代码可读
  • 指向成员函数的指针与函数指针的类型不同
  • @Tim,这就是我想我迷路的原因......我不明白我需要传递什么类型才能在function 中调用MethA
  • 是您将其传递给您编写的函数吗?如果没有,那么你需要一个包装函数。

标签: c++ class pointers


【解决方案1】:

当你需要使用指向成员函数的指针时,你需要传递两个不同的东西:

  • 调用什么成员函数和
  • 在哪个实例上调用它。

在 C++ 中,您不能像您希望的那样将它们组合成一个结构:

A a;
bar(a.foo);

不是有效的 C++。

相反,您必须这样做:

A a;
bar(a, &A::foo)

并相应地声明和实现 bar():

void bar(A &a, void (A::*method)()) {
    a.*method();
}

【讨论】:

  • 通过将 (a.*method)() 包裹在 parens 中的 bar 正文中来实现这一点。
【解决方案2】:

如果您想了解如何正确使用成员函数指针,请参阅Arkadiy's 答案。

但是

根据 cmets 中的要求:如果您使用的编译器支持 lambda(有些没有完整的 C++11)。您可以执行以下操作,这看起来更像您尝试使用的语法。

您对function 的定义更改为:

template <typename F>
double function(F f, double x){
    return f(x);
};

接受可使用double 调用的参数的函数模板。

在您的呼叫站点,您可以这样做:

A a(/*constructor arguments*/);
function([&](double x){return a.MethA(x);},1.0);

这会在原地生成一个函数对象,该对象通过引用绑定到您的类实例a

模板可以通过&lt;type_traits&gt; 中的一些魔法实现完全类型安全,但如果你传递了一些非常错误的东西,它会导致模板溢出。

【讨论】:

  • 我不明白为什么这被否决了
【解决方案3】:

它必须是一个静态函数!

#include <iostream>
#include <cassert>
class A {
public:
  static double MethA(double x) { return 5 * x; }
};
typedef double (*ftype)(double);
double function(ftype f) {
  assert(f != NULL);
  return f(7);
}
int main(int, char**) {
  // expect "35\n" on stdout
  std::cout << function(A::MethA) << "\n";
}

它必须是静态的,因为你不能在不知道你指的是哪个 A 对象的情况下访问 A 的任何变量!如果需要 A 的非静态成员变量,则需要将 a 的引用传递给静态函数:

#include <iostream>
#include <cassert>
class A {
  double fX;
public:
  A(double x) : fX(x) { }
  double methB(double x) const { return fX * x; }
  static double MethB(double x, const A& a) {
    return a.methB(x);
  }
};
typedef double (*ftype2)(double, const A&);
double function_with_context(ftype2 f, const A& a) {
  assert(f != NULL);
  return f(7, a);
}

int main(int, char**) {
  A a(6);
  // expect "42\n" on stdout
  std::cout << function_with_context(A::MethB, a) << "\n";
}

但有时最好使用继承和多态来实现这种接口:

#include <iostream>
class MyInterface {
public:
  virtual double f(double x) const = 0;
};

class A : public MyInterface {
  double fX;
public:
  A(double x) : fX(x) { }
  double f(double x) const {
    return fX * x;
  }
};

double function(const MyInterface& o) {
  return o.f(7);
}

int main(int, char**) {
  A a(6);
  // expect "42\n" on stdout
  std::cout << function(a) << "\n";
}

【讨论】:

  • 好的,这个解决方案对我有用......但我不明白将方法声明为静态的效果。是好的编程吗?如果我的课程是课程模板,它会起作用吗?
  • 这意味着您无法访问 A 的任何变量。毕竟,你指的是哪个 A 对象?
猜你喜欢
  • 2020-12-12
  • 2013-03-16
  • 2013-08-11
  • 2019-08-17
  • 2021-12-10
  • 2021-12-18
  • 2013-11-18
  • 2010-11-19
  • 1970-01-01
相关资源
最近更新 更多