Определение функции члена при построении объекта

У меня есть класс, в котором мне нужна функция, которую я могу определить для каждого объекта. Я хотел бы иметь возможность определять конкретные функции каждого объекта при определении вектора указанных объектов. Эти векторы моего объекта составят часть библиотеки. Вот неудачный пример того, что я пытаюсь сделать:

#include <iostream>
#include <vector>

class FunctionEater {

public:

    virtual double func() {}

    FunctionEater(double (*Func)) {

        func = Func;    // Not sure of the correct syntax here
    }
};

std::vector<FunctionEater> gorgers {

    {
        double () {    // Not sure of the syntax here, or if there is even syntax to do this

            double result = 0.794 * 739.775;
            return result;
        }
    },

    {
        double () {

            double temp1 = 0.794 * 739.775;
            double result = temp1 + 0.62;
            return result;
        }
    }
}

int main()
{
    double snackCrumbs = gorgers[0].func();
    double gorgePoop = gorgers[1].func();

    std::cout << snackCrumbs << std::endl << gorgePoop << std::endl;
}

Итак, две вещи, которые я пытаюсь выяснить или найти много документации, заключаются в следующем:

  • Как определить функцию при определении элементов gorgers[]
  • Как принять функцию, которую я передал конструктору как (*Func), и сохранить ее как виртуальный double func()

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

Я признаю, я также не знаю, правильно ли (* Func) при использовании виртуальной функции, но это адаптация с моей первой попытки с использованием указателей на функции. Я также рад принять альтернативные предложения, которые могут работать лучше, чем метод, который я пытаюсь использовать.

Заранее благодарим за любую помощь, которую вы можете предложить, и я с удовольствием отредактирую или обновлю мой вопрос, если это необходимо.

Пит

2 ответа

Что вы хотите, так это лучшая поддержка функциональных возможностей на вашем языке. К счастью, вы используете C++!

После C++11 у нас есть лямбды и std::function объекты, которые представляют объекты полиморфной функции во время выполнения.

Лямбда определяется так:

auto yourSecondFunc = [](){
        double temp1 = 0.794 * 739.775;
        double result = temp1 + 0.62;
        return result; 
};

Я был ленив и использовал авто там, но на самом деле, мы могли бы назначить его на std::function объект:

std::function<double()> yourSecondFunc = [](){
        double temp1 = 0.794 * 739.775;
        double result = temp1 + 0.62;
        return result; 
};

Тот std::function<double()> означает, что функция не принимает аргументов и возвращает двойной. Однако обратите внимание, что тип лямбда не является std::function объект, но это не место, чтобы обсудить это.

Таким образом, вы можете хранить std::function<double()> в вашем FunctionEater учебный класс:

class FunctionEater {

public:

    std::function<double()> func;

    FunctionEater(const std::function<double()>& f) {

        func = f;
    }

    void callMe() { double res = func(); } // how a function object is used
};

Тогда ваш вектор становится таким:

std::vector<FunctionEater> gorgers {
    FunctionEater { []() 
      {
        double result = 0.794 * 739.775;
        return result;
      }
    },
    FunctionEater { []() 
      {
        double temp1 = 0.794 * 739.775;
        double result = temp1 + 0.62;
        return result;
      }
    }
};

И ваш main? Это на самом деле то же самое:

int main()
{
    double snackCrumbs = gorgers[0].func();
    double gorgePoop = gorgers[1].func();

    std::cout << snackCrumbs << std::endl << gorgePoop << std::endl;
}

Правильный синтаксис:

#include <iostream>
#include <vector>
#include <functional>

struct FunctionEater
{
    using Func = double (*)();
    //using Func = std::function<double()>;

    template<typename F>
    FunctionEater(F f): func(f) {}

    Func func;
};

std::vector<FunctionEater> const gorgers = {
    []{ return 0.794 * 739.775; },
    []{ return 0.794 * 739.775 + 0.62; }
};

int main()
{
    double snackCrumbs = gorgers[0].func();
    double gorgePoop = gorgers[1].func();

    std::cout << snackCrumbs << std::endl << gorgePoop << std::endl;
}

Вы можете использовать любое определение Func, Указатель на функцию имеет меньше накладных расходов, но он может работать только с лямбда без захвата. std::function гораздо более гибкий.

NB. Я не уверен, почему инициализация вектора не работает без конструктора шаблона для FunctionEater, но я обнаружил, что в этом случае инициализаторы вектора должны быть явно преобразованы (либо в Func или же FunctionEater).

Другие вопросы по тегам