Определение цели оператора [] Использование - PullRequest
2 голосов
/ 20 января 2011

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

Datatype& operator[](const unsigned int Index) // I know this should use size_t instead.
{
    return *(BasePointer + Index); // Where BasePointer is the start of the array.
}

Я хотел бы реализовать некоторую проверку границ для использования MyInstance[Index] = Value, чтобы контейнер изменял размер автоматически, еслипользователь пытается изменить значение вне его диапазона.Однако я хочу, чтобы что-то еще произошло, если пользователь пытается получить доступ к значению вне диапазона контейнера, например, MyVariable = MyInstance[Index].Как я могу определить, как используется operator[]?

Ответы [ 3 ]

5 голосов
/ 20 января 2011

Эскиз:

возвращает прокси-объект вместо фактического ввода данных.Затем прокси-объект определяет operator = для обработки случая назначения и оператор неявного преобразования для случая чтения.

template <typename T>
class AccessorProxy {
  friend class Container<T>;
public:
    AccessorProxy(Container<T>& data, unsigned index)
        : data(data), index(index) { }
    void operator =(T const& new_value) {
        // Expand array.
    }
    operator const T&() const {
        // Do bounds check.
        return *(data.inner_array + index);
    }
private:
    AccessorProxy(const AccessorProxy& rhs)
     : data(rhs.data), index(rhs.index) {}
    AccessorProxy& operator=(const AccessorProxy&);
    Container<T>& data;
    unsigned index;
};

template <typename T>
class ConstAccessorProxy {
  friend class Container<T>;
public:
    ConstAccessorProxy(const Container<T>& data, unsigned index)
        : data(data), index(index) { }
    operator const T&() const {
        // Do bounds check.
        return *(data.inner_array + index);
    }
private:
    ConstAccessorProxy(const ConstAccessorProxy& rhs)
     : data(rhs.data), index(rhs.index) {}
    ConstAccessorProxy& operator=(const ConstAccessorProxy&);
    const Container<T>& data;
    unsigned index;
};

AccessorProxy<Datatype> operator[](const unsigned int Index)
{
    return AccessorProxy<Datatype>(*this, Index);
}
ConstAccessorProxy<Datatype> operator[] const (const unsigned int Index)
{
    return ConstAccessorProxy<Datatype>(*this, Index);
}

Вероятно, классы средства доступа должны быть друзьями класса контейнера.

Поиск способов избежать дублирования кода оставлен читателю в качестве упражнения.:)

2 голосов
/ 20 января 2011

Используйте фиктивный тип класса для представления выражений типа MyInstance[Index] и откладывайте поиск того, что делать, до тех пор, пока это выражение не будет использовано.

class MyContainer {
private:
    class IndexExpr {
    public:
        // Get data from container:
        operator const Datatype&() const;
        // Expand container if necessary, then store data:
        Datatype& operator=(const Datatype& value);

        // Treat MyInstance[i] = MyInstance[j]; as expected:
        Datatype& operator=(const IndexExpr& rhs)
        { return *this = static_cast<const Datatype&>(rhs); }
    private:
        IndexExpr(MyContainer& cont, unsigned int ind);
        MyContainer& container_;
        unsigned int index_;
        friend class MyContainer;
    };

public:
    IndexExpr operator[](unsigned int Index)
    { return IndexExpr(*this, Index); }

    // No IndexExpr needed when container is const:
    const Datatype& operator[](unsigned int Index) const;

    // ...
};
1 голос
/ 20 января 2011

Это не идеальный ответ на вопрос «как обнаружить», но, если пользователь обращается к operator[] через экземпляр const, выдается исключение, если индекс выходит за пределы.то есть

Datatype const& operator[]() const { .. // don't modify here, throw exception

Однако, если пользователь обращается к экземпляру через неконстантный экземпляр, он непременно расширяется, если индекс выходит за пределы (и находится в допустимых пределах)

Datatype& operator[]() { .. // modify here

По сути, вы используете атрибут const экземпляра, чтобы определить, какой будет ваша семантика (как это было сделано в std::map - т.е. попытка вызвать operator[] для экземпляра const карты приводит к ошибке компилятора - т.е.для карты нет константного значения operator[], поскольку функция гарантированно создает отображение, если ключ еще не существует.)

...