Передача указателя методу класса в качестве аргумента функции

У меня есть класс

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

И я хочу передать метод MethA в функцию, которая принимает указатель на функцию:

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

Так что я делаю это, чтобы позвонить

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

но он не компилируется.

Я почти уверен, что на этот вопрос ответят где-то в другом месте, но я не мог найти, потому что я не уверен, что используемая терминология правильная. Я пытаюсь передать указатель на метод класса в качестве аргумента функции? Или, чтобы передать указатель функции как член класса... Я смущен :-(

3 ответа

Когда вам нужно использовать указатель на функцию-член, вам необходимо передать две отдельные вещи:

  • какая функция-член для вызова и
  • в каком экземпляре это можно назвать.

В C++ вы не можете объединить их в одну конструкцию, как вы хотите:

A a;
bar(a.foo);

недействительно C++.

Вместо этого вы должны сделать это:

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

И объявите и выполните bar() соответственно:

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


См . Ответ Аркадия, если вы хотите увидеть, как правильно использовать указатели функций-членов.

НО

В соответствии с запросом в комментариях: если используемый вами компилятор поддерживает lambdas (некоторые без полного С++ 11 делают). Вы можете сделать что-то вроде следующего, что больше похоже на синтаксис, который вы пытаетесь использовать.

Ваше определение function меняет что-то вроде:

template <typename f="">
****** function(F f, ****** x){
 return f(x);
};
</typename>

шаблон функции, который принимает параметр, который можно вызывать с ******.

На вашем сайте вы сделаете следующее:

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

Это создает функциональный объект на месте, привязанный к вашему классу экземпляр a по ссылке.

Шаблон можно сделать полностью типичным с некоторой магией в , но как-то он даст вам шаблон, если вы передадите что-то очень неправильное.


Это должна быть статическая функция!

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

Он должен быть статичным, потому что вы не можете получить доступ к любой из переменных A, не зная, к какому объекту вы обращаетесь! Если вам нужны нестатические переменные-члены, вам необходимо передать ссылку на a в статическую функцию:

#include <iostream>
#include <cassert>
class A {
 ****** fX;
public:
 A(****** x) : fX(x) { }
 ****** methB(****** x) const { return fX * x; }
 static ****** MethB(****** x, const A& a) {
 return a.methB(x);
 }
};
typedef ****** (*ftype2)(******, const A&);
****** 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";
}
</cassert></iostream>

Но иногда лучше использовать наследование и полиморфизм для достижения такого интерфейса:

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

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

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

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

licensed under cc by-sa 3.0 with attribution.