Передача функции-члена класса глобальной функции в качестве аргумента

Я пытаюсь передать функцию-член класса A глобальной функции в качестве параметра. Что я должен сделать, чтобы это сработало? Кроме того, это хорошая идея? Контекст: я хочу сделать это, потому что (синоним) doSomething(...) — это очень общая функция, которая используется в main(), а также в других классах. Таким образом, я могу избежать нескольких копий одного и того же кода в своем проекте. Каковы альтернативы (если это не оптимально)?

#include <iostream>
using namespace std;

double doSomething(int i, double (*f)(double)) { return (*f)(i); }

class A{
public:
    A(double x) : number(x) {}
    double times(double i) { return ::doSomething(i, &A::multiply);} //calles the global function and gives a member function as parameter
    double multiply(double i) {return number*i;}
private:
    double number;
};

int main() {

    A obj(5.0);
    cout << obj.times(3.5) <<endl;

    return 0;
}

Компилятор жалуется:

../src/test5.cpp: In member function ‘double A::times(double)’:
../src/test5.cpp:17:63: error: cannot convert ‘double (A::*)(double)’ to ‘double (*)(double)’ for argument ‘2’ to ‘double doSomething(int, double (*)(double))’
  double times(double i) { return ::doSomething(i, &A::multiply);} //calles the global function and gives a parameter member function as parameter
                                                               ^
../src/test5.cpp:17:65: warning: control reaches end of non-void function [-Wreturn-type]
  double times(double i) { return ::doSomething(i, &A::multiply);} //calles the global function and gives a parameter member function as parameter

person dani    schedule 28.03.2014    source источник


Ответы (3)


Ваша функция doSomething ожидает указатель на свободную функцию (свободная функция означает функцию, не являющуюся членом). Вы пытаетесь передать ему указатель на функцию-член. Так не пойдет. Почему? Когда у вас есть свободная функция, скажем, void f(double), вы можете просто вызвать ее:

f(3.14);

с другой стороны, когда у вас есть функция-член (и нестатическая), для ее вызова вам нужен объект, например:

obj.m(3.14);

и вы не можете вызывать функцию-член без объекта. Таким образом, функция-член не может использоваться взаимозаменяемо со свободной функцией, поскольку они вызываются по-разному. Подумайте о вызове (*f)(i) в функции doSomething — к какому объекту A будет обращаться multiply?

Ваш дизайн нуждается в переосмыслении. Если вы хотите поделиться кодом, возможно, вам нужна какая-то иерархия классов и общий код в базовом классе?

person Wojtek Surowka    schedule 28.03.2014

С С++ 11 вы можете сделать:

#include <functional>

typedef std::function<double (double)> do_something_function;
double doSomething(double i, do_something_function f) { return f(i); }

class A{
    public:
    A(double x) : number(x) {}
    double times(double i) {
        do_something_function f = [this] (double i) {
            return this->multiply(i);
        };
        return ::doSomething(i, f);
    }
    double multiply(double i) {
        return number * i;
    }

    private:
    double number;
};
person Community    schedule 28.03.2014

То, как вы вызываете non-static функцию-член класса с помощью указателя, отличается от того, как вы делаете это для отдельной функции, потому что требуется указатель на экземпляр.

#include <iostream>
using namespace std;

class A;
typedef double (A::*f)(double);
double doSomething(double i, f p, A* ap);

class A {
public:

    A(double x) : number(x) {
    }

    double times(double i) {
        return ::doSomething(i, &A::multiply, this);
    } //calles the global function and gives a member function and pointer to A

    double multiply(double i) {
        return number*i;
    }
private:
    double number;
};

double doSomething(double i, double (A::*fp)(double), A* ap) {
    return (ap->*fp)(i);  // call *fp on *ap
}

int main() {

    A obj(5.0);
    cout << obj.times(3.5) << endl;

    return 0;
}

пример

person 4pie0    schedule 28.03.2014
comment
В вашем примере мне все равно нужно будет указать тип объекта, который хочет doSomething. Это означает, что мне все равно понадобится копия того же кода для другого объекта. Думаю, Войтек Суровка был прав, собираясь переосмыслить мой дизайн. Спасибо за ваш ответ. - person dani; 28.03.2014