Оберните вектор STL и измените поведение его итератора - PullRequest
6 голосов
/ 19 октября 2011

Есть такой код:

#include <iostream>
#include <vector>

template <class T>
class A{
public:   
    class iterator : public  std::vector<T>::iterator{
    public:
        T& operator*(){
            ??
        }
    };

    iterator begin(){
        return v.begin(); // error
    }

    iterator end(){
        return v.end(); // error
    }

    void add(const T& elem){
        v.push_back(elem);
    }

private:
    std::vector<T> v;
};

int main() {
    A<int> a;
    a.add(2);
    a.add(4);
    for(A<int>::iterator it = a.begin(); it != a.end(); ++it){
        std::cout << *it << std::endl;
    }
    return 0;
} 

Это оболочка для std::vector с моими собственными дополнительными функциями. Я хотел бы использовать итератор std::vector, однако я хочу только изменить поведение operator* для итератора:

T& operator*(){
  // do some additional function
  // normal behavior, return value of some element in vector
            ??
}

Как я могу использовать std::vector и его итератор с модификацией только operator*? Я хотел бы также обернуть функции, такие как begin() и end() для итератора, как правильно обернуть их?

EDIT:

Используя подсказки из ответов в этой теме, мне удалось решить мою проблему следующим образом:

#include <iostream>
#include <vector>

template <class T>
class A {
public:

    class iterator : public std::vector<T>::iterator {
    public:

        iterator(typename std::vector<T>::iterator c) : std::vector<T>::iterator(c) {
        }

        T& operator*() {
            std::cout << "Im overloaded operator*\n";
            return std::vector<T>::iterator::operator *();
        }
    };

    iterator begin() {
        return iterator(v.begin());
    }

    iterator end() {
        return iterator(v.end());
    }

    void add(const T& elem) {
        v.push_back(elem);
    }

private:
    std::vector<T> v;
};

int main() {
    A<int> a;
    a.add(2);
    a.add(4);

    for (A<int>::iterator it = a.begin(); it != a.end() ; ++it) {
        std::cout << *it << std::endl;
    }
    return 0;
} 

Может быть, это кому-нибудь пригодится.

Ответы [ 4 ]

3 голосов
/ 19 октября 2011

Обтекание итераторов stdlib лучше всего выполняется с помощью адаптеров итераторов. Эта задача далеко не тривиальна, и для ее упрощения есть библиотека Boost.Iterator . Возможно, один из предоставленных итераторов уже решает вашу проблему.

Если вы собираетесь написать это самостоятельно (я действительно не рекомендую этого), вы должны реализовать свой собственный итератор и сделать его конструктивным из vector::iterator, затем перегрузить все необходимые операторы, чтобы соответствовать требованиям концепции, которую моделирует ваш новый итератор. Также наследуйте от std::iterator, чтобы черты работали. Не забудьте иметь константный вариант. В этой книге есть глава, посвященная разработке собственных итераторов. Также получите копию стандарта (C ++ 03 или C ++ 11, здесь не имеет большого значения). Вам это понадобится.

1 голос
/ 19 октября 2011

Один не наследуется от std::vector<T>::iterator, поскольку он не должен быть классом.В некоторых реализациях это просто typedef для T*, и его нельзя наследовать от указателя.Также не следует наследовать от стандартных контейнеров, поскольку в них отсутствует виртуальный деструктор;существует возможность наследования способом private или protected и сделать все символы и функции видимыми с помощью typedef и using.В конце вам придется переписать весь вектор и его итераторы, которые перенаправляют вызовы в базовую реализацию.

1 голос
/ 19 октября 2011

К сожалению, единственный способ сделать это - написать полную оболочку для std::vector и его итераторов. Это много работы.

0 голосов
/ 19 октября 2011

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

Однако при разыменовании итератора нет никакого интуитивного понимания того, какими будут дополнительные побочные эффекты для вашего класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...