Дайте унаследованному вложенному классу отдельный тип данных в C++
Я пытаюсь имитировать способ объявления итераторов STL с помощью наследования и вложенных классов.
У меня есть родительский класс Iterable
с вложенным классом iterator
,
class Iterable
{
public:
class iterator
{ };
};
У меня есть два класса, List
а также Vector
которые наследуют от Iterable
чтобы получить вложенный класс iterator
,
class List : public Iterable
{ };
class Vector : public Iterable
{ };
Это позволяет объявлять итераторы подобным образом.
List::iterator lIte;
Vector::iterator vIte;
Однако я хотел бы иметь ошибки времени компиляции при попытке смешать итераторы из разных производных классов. Например
lIte = vIte; // throw a compile error
Но, так как iterator
s происходят из того же базового класса, Iterable
, заявление выше будет скомпилировано просто отлично.
Примером обходного решения может быть определение нового вложенного класса iterator
который унаследует от Iterable::iterator
в каждом классе, который наследует от Iterable
(List
а также Vector
). Например
class List : public Iterable
{
public:
class iterator : Iterable::iterator // This "specializes" the datatype of iterator
{ };
};
class Vector : public Iterable
{
public:
class iterator : Iterable::iterator
{ };
};
Выполнение вышеупомянутого успешно вызовет ошибку времени компиляции при попытке:
List::iterator lIte;
Vector::iterator vIte;
lIte = vIte;
Однако это неоптимальная работа:
- Это включает в себя дублирование кода в каждом классе, который наследует от
Iterable
, - Требуется C++11 для дублирования
iterator
классы для наследования соответствующих конструкторовIterable::iterator
,
Мой вопрос, как я могу сделать List::iterator
а также Vector::iterator
различные типы без дублирования кода или использования наследования конструктора C++11?
1 ответ
Вы можете использовать шаблон класса для генерации разных классов из одного общего шаблона:
template<typename T>
struct Iterable
{
class iterator
{ };
};
class List : public Iterable<List>
{ };
class Vector : public Iterable<Vector>
{ };
Однако, хотя это решает вашу непосредственную проблему, это не выглядит как правильное решение.
На самом деле не имеет смысла давать Iterable
класс итератора вообще, если это не (потенциально полиморфный) базовый класс. В конце концов, перебирая vector
работает не так, как перебирать list
,
Поскольку вы хотите имитировать стандартную библиотеку C++, вы должны знать, что ::std::list
а также ::std::vector
не делиться общедоступными базовыми классами.