std :: bind и std :: function с полиморфизмом, базовый класс - PullRequest
3 голосов
/ 23 апреля 2020

Я пытаюсь привязать объект к функции, но вызывается функция базового класса. Код это просто пример для реального кода. У меня будет только строка позже в реальном коде.

 class A {
    public:
        virtual void f(const std::string &s) {
            std::cout << "A " << s << std::endl;
        }
    };

    class B : public A {
    public:
        void f(const std::string &s) override {
            std::cout << "B " << s << std::endl;
        }
    };

    void main() {
        std::unique_ptr<A> a = std::make_unique<B>();

        std::function<void(const std::string &)> callback
                =  std::bind(&A::f, *a, std::placeholders::_1);
        callback("my string");
    }

В результате

 A my string

Я попытался изменить ее на & B: f, но получил ошибку.

No viable conversion from 'typename _Bind_helper<__is_socketlike<void (B::*)(const basic_string<char> &)>::value, void (B::*)(const basic_string<char> &), A &, const _Placeholder<1> &>::type' (aka '_Bind<void (Centerity::Cluster::Correlation::B::*(Centerity::Cluster::Correlation::A, std::_Placeholder<1>))(const std::basic_string<char> &)>') to 'std::function<void (const std::string &)>' (aka 'function<void (const basic_string<char> &)>')

Я пытался изменить его на A* a = B(); тот же результат. Не могу найти подобный код нигде. Конечно, создание B b вызовет B::f, но это мне не поможет.

Я могу потерять связь и использовать лямбду, но я не знаю как.

Ответы [ 2 ]

7 голосов
/ 23 апреля 2020

ПРИМЕЧАНИЕ:

Я не знаю, какой компилятор вы используете, но main не должен быть пустым. Я исправил это в моем коде ниже:

#include <memory>
#include <iostream>
#include <functional>

class A {
public:
    virtual void f(const std::string &s)
    {
        std::cout << "A " << s << std::endl;
    }
};

class B: public A {
public:
    void f(const std::string &s) override 
    {
        std::cout << "B " << s << std::endl;
    }
};

int main() 
{
    std::unique_ptr<A> a = std::make_unique<B>();
    auto callback = std::bind(&A::f, a.get(), std::placeholders::_1);

    callback("my string");
    return 0;
}

Выходы:

B my string

Уловка состоит в том, чтобы передать указатель на базовый класс (указывающий на объект производного класса) на std::bind(&A::f, a.get(), std::placeholders::_1);.

Если вы передадите по значению, то будет создан новый объект вашего базового класса A (конструктор копирования), и будет вызвана версия f базового класса, как вы наблюдали в своей программе.

1 голос
/ 23 апреля 2020

Как вы просите лямбда версия:

class A { 
    public:
        virtual void f(const std::string &s) {
            std::cout << "A " << s << std::endl;
        }   
};  

class B : public A { 
    public:
        void f(const std::string &s) override {
            std::cout << "B " << s << std::endl;
        }
};  

int main() {
    std::unique_ptr<A> a = std::make_unique<B>();

    auto callback = [&a](const std::string& s){ return a->f(s); };

    callback("my string");
}
...