У меня есть класс, который включает станд.:: список и желание предоставить общественности начинаются () и конец () для const_iterator, и частный начинаются () и конец () для просто итератора.
Однако компилятор видит частную версию и жалуясь, что это является частным вместо того, чтобы использовать общедоступную версию константы.
Я понимаю, что C++ не перегрузится на типе возврата (в этом случае const_iterator и итератор), и таким образом он выбирает версию неконстанты, так как мой объект не является константой.
За исключением кастинга моего объекта к константе перед вызовом начинаются (), или не перегрузка имени начинаются, там способ выполнить это?
Я думал бы, что это - известный шаблон, который люди решили прежде и хотели бы следовать примеру относительно того, как это обычно решается.
class myObject {
public:
void doSomethingConst() const;
};
class myContainer {
public:
typedef std::list<myObject>::const_iterator const_iterator;
private:
typedef std::list<myObject>::iterator iterator;
public:
const_iterator begin() const { return _data.begin(); }
const_iterator end() const { return _data.end(); }
void reorder();
private:
iterator begin() { return _data.begin(); }
iterator end() { return _data.end(); }
private:
std::list<myObject> _data;
};
void myFunction(myContainer &container) {
myContainer::const_iterator itr = container.begin();
myContainer::const_iterator endItr = container.end();
for (; itr != endItr; ++itr) {
const myObject &item = *itr;
item.doSomethingConst();
}
container.reorder(); // Do something non-const on container itself.
}
Ошибка из компилятора - что-то вроде этого:
../../src/example.h:447: error: `std::_List_iterator<myObject> myContainer::begin()' is private
caller.cpp:2393: error: within this context
../../src/example.h:450: error: `std::_List_iterator<myObject> myContainer::end()' is private
caller.cpp:2394: error: within this context
Спасибо.
- William
Я думаю, ваш единственный вариант - переименовать частные методы (если они вам вообще нужны).
Кроме того, я считаю, что вам следует переименовать typedefs:
class MyContainer
{
public:
typedef std::list<Object>::const_iterator iterator;
typedef iterator const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
typedef std::list<Object>::iterator _iterator;
_iterator _begin();
_iterator _end();
...
};
Контейнеры должны использовать typedef как итератор
, так и const_iterator
. Универсальная функция, принимающая неконстантный экземпляр вашего контейнера, может рассчитывать на использование итератора итератора
typedef - даже если она не собирается изменять элементы. (Например, BOOST_FOREACH
.)
Это будет нормально с точки зрения корректности констант, потому что если общая функция действительно попытается изменить объекты, реальный тип итератора (являющийся const_iterator
) не позволил бы.
В качестве теста следующий должен скомпилироваться с вашим контейнером:
int main()
{
myContainer m;
BOOST_FOREACH(const myObject& o, m)
{}
}
Обратите внимание, что m не является константой, но мы только пытаемся получить константные ссылки на содержащиеся типы, поэтому это должно быть разрешено .
Плохая идея наследовать от std :: list (он не предназначен для наследования).
Используйте переменную-член типа std :: list.
class myContainer
{
std::list<myObject> m_data;
public:
typedef std::list<myObject>::const_iterator myContainer::const_iterator;
private:
typedef std::list<myObject>::iterator myContainer::iterator;
public:
myContainer::const_iterator begin() const
{
return m_data.begin();
}
myContainer::const_iterator end() const
{
return m_data.end();
}
private:
myContainer::iterator begin()
{
return m_data.begin();
}
myContainer::iterator end()
{
return m_data.end();
}
};
Вам необходимо изменить имя частного начального конца. Компилятор не может различать только возвращаемый тип
Это работает для меня: обратите внимание на имена _begin _end
#include <list>
class myObject {};
class myContainer : private std::list<myObject> {
public:
typedef std::list<myObject>::const_iterator const_iterator;
private:
typedef std::list<myObject>::iterator iterator;
public:
myContainer::const_iterator begin() const {
return std::list<myObject>::begin();
}
myContainer::const_iterator end() const {
return std::list<myObject>::end();
}
private:
myContainer::iterator _begin() {
return std::list<myObject>::begin();
}
myContainer::iterator _end() {
return std::list<myObject>::end();
}
};
void myFunction(myContainer &container) {
myContainer::const_iterator aItr = container.begin();
myContainer::const_iterator aEndItr = container.end();
for (; aItr != aEndItr; ++aItr) {
const myObject &item = *aItr;
// Do something const on container's contents.
}
}
int main(){
myContainer m;
myFunction(m);
}
Возможно, вы захотите изменить сигнатуру вашего метода Myfunction на такую:
void myFunction(const myContainer &container)
потому что метод const будет вызываться только на объекте const. В настоящее время происходит то, что вы пытаетесь вызвать не const-метод, который в вашем случае является приватным.