У меня есть особый класс, в котором хранятся данные, реализующие интерфейс:
template<typename T>
class MyContainer : public Container<T> {
class Something : public IInterface {
public:
// implement *, ->, and ++ here but how?
private:
T x;
};
// implement begin and end here, but how?
private:
Something* data; // data holds the array of Somethings so that references to them can be returned from begin() and end() to items in this array so the interface will work, but this makes the problem described below
};
И у меня есть массив Something
s.
Мне нужно Something
для реализации класса интерфейса ( IInterface
в примере), который:
* retval
возвращает ссылку на член x
, retval ->
возвращает адрес x
и ++ retval
заставляет retval
ссылаться на следующее Something
в массиве. контейнер [i]
(где контейнер
- это массив, содержащий объекты Something
) всегда возвращает что-то такое, что * retval
всегда возвращает ссылку на тот же T
для тот же i
. Прямо сейчас интерфейс выглядит следующим образом:
template<typename T>
class Container {
class IInterface {
public:
virtual T& operator*() = 0;
virtual T* operator->() = 0;
virtual IInterface& operator++(); // this is the problem
};
// returning a reference right now to support covariance, so subclasses can
// derive from Container and then have a member class derive from IInterface
// and override these to return their derived class, but this has a problem
virtual IInterface& begin() = 0;
virtual IInterface& end() = 0;
};
Мое текущее решение (пусть виртуальные методы возвращают IInterface &
и возвращают Something &
в реализации) не имеет проблем с требованиями, за исключением для требования ++ retval
. Поскольку Something
напрямую привязан к удерживаемому объекту и не может указывать на T
с помощью указателя, я не могу найти способа получить ++
, чтобы переменная ссылалась на следующее что-то
в массиве.
Если это помогает, это система типа итератора. Я бы сделал это с помощью итераторов в стиле STL (где у вас есть просто массив T
), которые передаются по значению и содержат указатели на значения, которые они представляют, но это нарушит интерфейс, потому что только ссылки указатели и указатели ковариантны, и объекты уже должны существовать где-то еще (в моем коде они находятся в массиве), поэтому вы не возвращаете ссылку на локальный объект.
Цель этой настройки состоит в том, чтобы можно написать функции, которые принимают Контейнер и
и перебирают контейнер, не зная, какой это тип контейнера:
void iterate(Container<int>& somecontainer) {
Container<int>::IIterator i = somecontainer.begin(); // right now this would return a reference, but it doesn't/can't work that way
while (i != somecontainer.end()) {
doSomething(*i);
++i; // this is the problem
}
}
Мне сложно описать это, не стесняйтесь сообщить мне, если вам нужно дополнительная информация.