Как вызвать const_iterator для неконстантного класса?[дубликат]

StackOverflow https://stackoverflow.com//questions/21017654

  •  21-12-2019
  •  | 
  •  

Вопрос

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

Я пытаюсь реализовать этот класс с именем Map.он должен содержать 2 итератора - iterator и const_iterator.

Я их реализовал - iterator наследует от const_iterator, и в Map class у меня есть следующие функции:

iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;

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

Map<std::string,int> msi;

...

// print map
for(Map<std::string,int>::const_iterator it = msi.begin(); it != msi.end(); ++it) {
// more stuff here
}

с msi является неконстантным экземпляром карты, msi.begin() звонки в iterator begin() и не const_iterator begin() const, что приводит к непреднамеренному поведению.

Предполагая, что с файлом примера все в порядке, как мне это сделать? msi.begin() называет правильный const_iterator функция?(учитывая это, итератор имеет тип const_iterator).

РЕДАКТИРОВАТЬ:Что касается разговора об автоматическом преобразовании, я решил добавить свои классы итераторов, пожалуйста, укажите на мою ошибку.

class Map {

    //...

    public:

        class const_iterator {

        private:

            Node* currNode;

        public:


            const_iterator(Node* cur_node = NULL) : currNode(cur_node) {}

            const_iterator& operator++() {
                currNode = currNode->next;
                return *this;
            }

            const_iterator operator++(int) {
                const_iterator old = *this;
                ++(*this);
                return old;
            }

            bool operator!=(const_iterator const& curr) {

                return !(*this == curr);
            }

            string operator*() {
                // this might cause memory leak
                string toString(this->currNode->key);
                std::stringstream s;
                int tmp = this->currNode->value;
                s << tmp;
                string secondString(s.str());
                toString = toString + ":" + secondString;
                return toString;
            }

            bool operator==(const_iterator const& curr) {
                return this->currNode == curr.currNode;
            }


            void operator=(const_iterator target) {
                this = target;
            }

            //void operator=(Node* target) {
            //    this->currNode = target;
            //}
        };

        class iterator : public const_iterator {

        private:

            Node* currNode;

        public:

            iterator(Node* cur_node = NULL) : currNode(cur_node) {}

            iterator& operator++() {
                currNode = currNode->next;
                return *this;
            }

            iterator operator++(int) {
                iterator old = *this;
                ++(*this);
                return old;
            }

            bool operator==(iterator const& curr) {
                return *this == curr;
            }

            bool operator!=(iterator const& curr) {

                return !(*this == curr);
            }

            string operator*() {
                // this might cause memory leak
                string toString(this->currNode->key);
                std::stringstream s;
                int tmp = this->currNode->value;
                s << tmp;
                string secondString(s.str());
                toString = toString + ":" + secondString;
                return toString;
            }

            void operator=(iterator target) {
                this = target;
            }

        };

        //..
}
Это было полезно?

Решение

Добавлены стандартные контейнеры C++11 cbegin и cend для этой цели.В отсутствие этого вы, очевидно, всегда можете привести свой объект к const& явно, чтобы получить const просмотр на объекте.

Однако более фундаментально нет причин, по которым ваш iterator не должен поддерживать автоматическое преобразование в const_iterator.Таким образом, вам вообще не нужно будет менять клиентский код.Фактически, ваш код уже должен поддерживать это, если, как вы сказали, iterator наследует от const_iterator.

Однако опубликованный вами код содержит несколько ошибок.Во-первых, operator= неверно, и вы должны были получить сообщение об ошибке.Исправленная версия:

void operator=(const_iterator target) {
    currNode = target.currNode;
}

Что еще более важно, ваше наследование не имеет смысла.Правда, ты делать наследовать iterator от const_iterator но ваш код делает вид, что этого никогда не было – iterator полностью переопределяет свой родительский класс и никак с ним не связан.

iterator скорее должно выглядеть примерно так:

class iterator : public const_iterator {
public:
    iterator(Node* cur_node = NULL) : const_iterator(cur_node) {}
};

Для этого, конечно, требуется currNode объявлен protected в const_iterator.Этот класс также совершенно бесполезен (как и ваш на данный момент), поскольку он не добавляет никакой функциональности в const_iterator сорт.Вам необходимо реализовать operator* что позволяет изменить его значение.Ваш текущий код принципиально не позволяет этого, поскольку он возвращает вновь созданную строку, а не (что-то вроде) ссылку на значение карты.

Кроме того, неясно, каким образом const_iterator класс получает не-const Node указатель в первую очередь.Это не должно быть возможно:в конце концов, он получает указатель от const Map.

Другие советы

Если вы определите msi

const Map<std::string,int> msi;

вместо

Map<std::string,int> msi;

будет вызвана константная версия Begin() и End()

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top