как реализовать общий функтор для нескольких классов в c++
Предположим, что у вас есть два (или более) класса с частными векторами членов:
class A {
private:
std::vector<X> priv_vec;
public:
//more stuff
}
class B {
private:
std::vector<Y> priv_vec;
public:
//more stuff
}
И у вас есть класс-функтор, который имеет состояние и работает на общем векторе (сортирует или подсчитывает элементы или что-то в этом роде). Состояние функтора инициализируется первым вектором, над которым он работает. Если функтор будет применен к другому вектору позже, он изменит свое поведение в зависимости от состояния (сортирует таким же образом или обрезает второй вектор после стольких элементов, сколько первый и т. д.)
, что является лучшим способом для реализации такого функтора (Дизайн-Шаблон или функционального интерфейса?) без предоставления частных векторов другим классам или пользователю классов?
Например: Пользователь хотел бы инициализировать этот функтор объектом класса A, а затем использовать этот инициализированный функтор для одного или нескольких объектов класса B. пользователь не может (и не должен) использовать частные векторы непосредственно в качестве аргументов функции для функтора.
3 ответа:
Хум, во-первых, остерегайтесь состояний в функторах.
Большинство STL-реализаций алгоритмов могут копировать ваши функторы, поэтому вам обычно приходится извлекать состояние во внешней структуре.
Теперь, для применения функторов, ну это просто: пусть ваши классы объявляют шаблонную функцию-член!
class A { public: template <class Functor> Functor Apply(Functor f); private: }; class B { public: template <class Functor> Functor Apply(Functor f); }; // Usage MyFunctor f; A a; B b; b.Apply(a.Apply(f));
Что касается функтора, если вам нужно Состояние:
// Alternative 1 class FunctorState {}; class Functor { public: Functor(FunctorState& state): m_state(state) {} // some operator()(...) private: FunctorState& m_state; }; // Alternative 2 class Functor { struct FunctorState {}; public: Functor(): m_state(new FunctorState) {} // some operator()(...) private: boost::shared_ptr<FunctorState> m_state; };
Таким образом, копии
Functor
все указывают на один и тот же экземплярFunctorState
. Просто выберите в зависимости от того, если вы действительно хотите получить доступ к состоянию вне класса или нет.
Выглядит как проблема импорта политик из объекта
class A
и их применения к объектамclass B
, с той лишь разницей, что все это делается во время выполнения (в отличие от типичного дизайна на основе политик). Возникает вопрос, Являются ли эти политики собственностьюclass A
или мы можем изолировать их и передавать по мере необходимости? Это должно упростить име.
Решение, основанное на шаблонах.
#include <iostream> #include <string> #include <vector> // Wraps up a vector of type T and exposes a // simple interface to access it. template <class T> class A { public: A(const std::vector<T>& v) : priv_vec(v) { } virtual size_t count() const { return priv_vec.size(); } virtual T operator[](size_t index) const { return priv_vec[index]; } private: std::vector<T> priv_vec; }; // A sample functor with state. // The state is the size and current index of the vector object. class Functor { public: Functor() : _size(0), _index(0) { } // Prints the element at the current index. // If the index exceeds size, it is reset to 0. template <class T> void operator()(const A<T>& b) { if (_size == 0) _size = b.count(); if (_index >= _size) _index = 0; std::cout << b[_index++] << '\n'; } private: size_t _size; size_t _index; }; int main() { // Some tests. std::vector<int> int_vec; int_vec.push_back(1); int_vec.push_back(2); int_vec.push_back(3); A<int> a(int_vec); std::vector<std::string> str_vec; str_vec.push_back("aaaa"); str_vec.push_back("bbbb"); str_vec.push_back("cccc"); A<std::string> b(str_vec); Functor f; f(a); // 1 f(b); // bbbb f(a); // 3 f(a); // 1 f(a); // 2 f(b); // cccc return 0; }