Интерфейсы и проблема ковариации

У меня есть особый класс, в котором хранятся данные, реализующие интерфейс:

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 в примере), который:

  1. Содержит чистые виртуальные функции-члены, которые возвращают что-то вроде что * retval возвращает ссылку на член x , retval -> возвращает адрес x и ++ retval заставляет retval ссылаться на следующее Something в массиве.
  2. Вещи, которые возвращают чистые виртуальные члены, могут быть унаследованы и возвращены реализацией членов
  3. контейнер [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
    }
}

Мне сложно описать это, не стесняйтесь сообщить мне, если вам нужно дополнительная информация.

7
задан Seth Carnegie 8 August 2011 в 05:03
поделиться