Могу ли я использовать указатели функций С++, такие как действие С#?

В C++ я впервые столкнулся с указателями на функции.
Я пытался использовать это, чтобы сделать его похожим на Action и Delegate в C#.
Однако при объявлении указателя на функцию необходимо указывать тип класс, в котором существует функция.
ex) void (A :: * F) ();
Могу ли я использовать указатель функции, который может хранить функцию-член любого класса?

Как правило, указатели на функции используются, как показано в приведенном ниже коде.

class A {
public:
    void AF() { cout << "A::F" << endl; }
};

class B {
public:
    void(A::*BF)();
};

int main()
{
    A a;
    B b;

    b.BF = &A::AF;
    (a.*b.BF)();

    return 0;
}

Я хочу использовать его, как код ниже.
возможно ли это?
Или есть что-то еще, чтобы заменить указатель функции?

class A {
public:
    void AF() { cout << "A::F" << endl; }
};

class B {
public:
    void(* BF)();
};

int main()
{
    A a;
    B b;

    b.BF = a.AF;

    return 0;
}

Я решил вопрос через ответ.
Спасибо!

#include <functional>
#include <iostream>

class A {
public:
    void AF() { std::cout << "A::F" << std::endl; }
};

class C {
public:
    void CF() { std::cout << "C::F" << std::endl; }
};

class B {
public:
    B(){}
    std::function<void()> BF;
};

int main() {
    A a;
    C c;
    B b;
    b.BF = std::bind(&A::AF, &a);
    b.BF();
    b.BF = std::bind(&C::CF, &c);
    b.BF();

    int i;
    std::cin >> i;
    return 0;
}

person Lim Seungwook    schedule 01.06.2019    source источник
comment
Почему бы вам просто не сделать AF статическим методом или глобальной функцией? В любом случае вам не нужно обращаться ни к одному члену класса A.   -  person user202729    schedule 01.06.2019
comment
В данный момент я не могу прочитать ответ с кодом, но вы можете прочитать этот ответ stackoverflow.com/questions/9568150 /what-is-ac-delegate И от меня почитайте про автоматический тип ane std::variant из C++ 17   -  person Drock    schedule 01.06.2019
comment
@Drock читал об автоматическом типе - auto не является типом. Это просто ключевое слово, сообщающее компилятору, что при инициализации переменной необходимо вывести правильный тип. Переменная по-прежнему имеет статический тип, и этот тип не может измениться. Например; int i = 42; и auto i = 42; дают точно одинаковые результаты. В обоих случаях тип i равен int, и он остается int навсегда.   -  person Jesper Juhl    schedule 01.06.2019
comment
@Drock Просто из интереса, почему стоит прочитать вариант?   -  person George    schedule 01.06.2019
comment
Вы можете использовать шаблон std::function для указателей на функции-члены. Тип шаблона не требует класса.   -  person Weak to Enuma Elish    schedule 01.06.2019


Ответы (2)


То, что вы хотите сделать, вероятно, похоже на это. Вы можете использовать std::function для хранения указателя на функцию-член, привязанную к конкретному экземпляру.

#include <functional>
#include <iostream>

class A {
public:
    void AF() { std::cout << "A::F" << std::endl; }
};

class B {
public:
    B(const std::function<void()>& bf) : BF(bf) {}
    std::function<void()> BF;
};

int main() {
    A a;
    B b1(std::bind(&A::AF, &a)); // using std::bind
    B b2([&a] { a.AF(); });      // using a lambda

    b1.BF();
    b2.BF();

    return 0;
}
person snak    schedule 01.06.2019
comment
std::bind это тааак старая школа. stackoverflow.com/q/1930903/5945883 Я бы проголосовал за ответ на основе лямбды. - person R2RT; 01.06.2019
comment
Ну, с лямбдой, теперь это уже не отвечает на вопрос, я думаю, потому что и захват лямбды с function<>, и вызов метода в лямбде тривиальны и ничего особенного. - person snak; 01.06.2019
comment
@snak Также более эффективен, чем bind, поскольку результирующий объект меньше и на практике не требует выделения памяти в std::function. - person StaceyGirl; 01.06.2019
comment
Я никогда не использовал лямбда-выражения, поэтому немного поискал и понял. Спасибо! - person Lim Seungwook; 01.06.2019
comment
@snak B b2([&a] { a.AF(); });, уже отредактированный Тедом, отвечает на вопрос на 100% и избавляет OP от головной боли, когда он решает добавить какой-либо аргумент в делегированную функцию. - person R2RT; 01.06.2019

Вот реализация принятого ответа в стиле С#. Он эффективен и гибок в памяти, поскольку вы можете создавать и делегировать в разных точках выполнения, что может ожидать разработчик С#:

#include <iostream>
#include <functional>

using namespace std;

class A {
public:
    void AF() { cout << "A::F" << endl; }
    void BF() { cout << "B::F" << endl; }
};

class B {
public:
    std::function<void()> Delegate;
};

int main() {
    A a;
    B b;

    b.Delegate = std::bind(&A::AF, &a);
    b.Delegate();

    b.Delegate = [&a] { a.BF(); };
    b.Delegate();
    return 0;
}
person Avin Kavish    schedule 01.06.2019
comment
Технически это более эффективно. Принятый ответ вынужден копировать-инициализировать элемент std::function из-за const& в конструкторе. В вашем случае он будет инициализирован напрямую без каких-либо временных объектов. - person R2RT; 01.06.2019
comment
Ох, ладно. Я тоже немного новичок в С++. Соответственно буду менять. - person Avin Kavish; 01.06.2019
comment
Я имею в виду, что вам не нужно ничего менять. - person R2RT; 01.06.2019
comment
Текст вверху :) - person Avin Kavish; 01.06.2019
comment
Я знаком со стилем C#, и это хороший ответ для меня. - person Lim Seungwook; 01.06.2019