Как вызвать const_iterator для неконстантного класса?[дубликат]
Вопрос
Я читал некоторые другие темы, связанные с этой проблемой, но не предложил решения моей проблемы.Я надеюсь, что вы, ребята, можете дать мне идеи или советы.
Я пытаюсь реализовать этот класс с именем 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()