Как перебрать список объектов производных функций и получить доступ к переменным-членам производных объектов - PullRequest
2 голосов
/ 02 мая 2020

У меня есть определение объекта функции:

struct BaseFunctor
{
    std::string desc = "Not this one!";
    virtual double operator()(double a, double (*func) (double)) = 0;
};

и набор определений производных объектов функции:

struct DerivedFunctor1 : public BaseFunctor
{
    std::string desc = "Yes this!";
    virtual double operator()(double a, double (*func) (double))
    {
        return a * func(a);
    }
};

struct DerivedFunctor2 : public BaseFunctor
{
    std::string desc = "This is also correct!";
    virtual double operator()(double a, double (*func) (double))
    {
        return 5 * a * func(a);
    }
};

Они создаются и используются следующим образом:

double f1(double x){
    return x*x+x;
}

template <typename T, typename F>
void do_something(T &func, F &derived)
{
    double a = 1.0;
    double res = derived(a, func);
    std::cout << derived.desc << std::endl;
    std::cout << "Result is: " << res << std::endl;

}

int main()
{
    std::vector<BaseFunctor*> functors;
    DerivedFunctor1 *derived1 = new DerivedFunctor1;
    DerivedFunctor2 *derived2 = new DerivedFunctor2;
    functors.push_back(derived1);
    functors.push_back(derived2);

    for (auto &f : functors)
    {
        do_something(f1, *f);
    }
}

Теперь причина, по которой два функциональных объекта были получены из BaseFunctor, заключалась в том, что я мог собрать их в стандартный контейнер и перебрать их. Существуют ли другие и более эффективные способы итерации по функциональным объектам?

Во-вторых, выполнение кода выводит

Not this one!
Result is: 2
Not this one!
Result is: 10

Когда я пытаюсь получить доступ к переменной-члену desc, я получаю член переменная родительского класса. Я мог бы написать геттеры и таким образом получить доступ к переменным-членам производных объектов-функций, но это кажется большой работой, если в объектах-функциях много переменных-членов. Есть ли другой способ добиться этого?

Ответы [ 2 ]

3 голосов
/ 02 мая 2020

Ваши производные классы определяют другого члена с именем desc в дополнение к существующему BaseFunctor::desc.

. Вам скорее всего нужно инициализировать BaseFunctor::desc с правильной строкой. Пример:

#include <iostream>
#include <memory>
#include <vector>

struct BaseFunctor {
    std::string const desc;
    virtual double operator()(double a, double (*func) (double)) = 0;
    virtual ~BaseFunctor() noexcept = default;
protected:
    BaseFunctor(std::string desc) noexcept
        : desc(move(desc))
    {}
};

struct DerivedFunctor1 : public BaseFunctor {
    DerivedFunctor1() : BaseFunctor("Yes this!") {}
    double operator()(double a, double (*func) (double)) override { return a * func(a); }
};

struct DerivedFunctor2 : public BaseFunctor {
    DerivedFunctor2() : BaseFunctor("This is also correct!") {}
    double operator()(double a, double (*func) (double)) override { return 5 * a * func(a); }
};

template <typename T>
void do_something(T &func, BaseFunctor &derived) {
    double a = 1.0;
    double res = derived(a, func);
    std::cout << derived.desc << '\n';
    std::cout << "Result is: " << res << '\n';
}

double f1(double a) noexcept { return a * a + a; }

int main() {
    using P = std::unique_ptr<BaseFunctor>;
    std::vector<P> functors;
    functors.push_back(P(new DerivedFunctor1));
    functors.push_back(P(new DerivedFunctor2));
    for (auto &f : functors)
        do_something(f1, *f);
}

Несколько других изменений:

  • BaseFunctor должен иметь деструктор virtual, если объекты производных классов удаляются через BaseFunctor*, и ваш код предполагает, что.
  • Переопределенные функции производных классов должны использовать override вместо virtual, чтобы компилятор перехватывал ошибки, если вы пытаетесь переопределить функцию, которая не существует или имеет другие параметры и / или тип возврата , С virtual он вводит новую функцию перегрузки с тем же именем, в данном случае.
  • std::unique_ptr используется, чтобы избежать ручной очистки и утечки памяти.
  • BaseFunctor::desc made const, так что он должен быть инициализирован в списке инициализаторов в BaseFunctor. Это также делает BaseFunctor не копируемыми и неподвижными, что позволяет избежать случайного копирования объектов производного класса с нарезкой.
2 голосов
/ 03 мая 2020

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

#include <iostream>

void call_all() {
    // Does nothing, just stops the recursion.
}

template<typename Current, typename... Args>
void call_all(Current current_function, Args... args) {
    current_function();
    call_all(args...);
}

void func1() {
    std::cout << "func1" << std::endl;
}

void func2() {
    std::cout << "func2" << std::endl;
}

int main() {
    // Pass anything that implements operator() here.
    call_all(func1, func2);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...