Рассмотрим следующий пример кода для класса связанного типа списка. Я хочу объявить метод, который возвращает итератор, который является typedef
для Node*
, Тем не мение, Node
является частным вложенным классом, поэтому для того, чтобы сделать typdef
, я должен сообщить компилятору о Node
с предварительной декларацией.
Наивно, я думал, что оба дефолта к частному сработают; что-то вроде этого:
class List
{
class Node;
typedef Node* Iterator;
public:
List() : head_(NULL), tail_(NULL) {}
Iterator begin() {return head_;}
private:
class Node
{
private:
int data_;
};
Node* head_;
Node* tail_;
};
int main()
{
List list;
List::Iterator = list.begin();
return 0;
}
что приводит к ошибке времени компиляции в строке 4:
‘typedef class List :: Node * List :: Iterator’ является приватным
компиляция прервана из-за ошибок -Wfatal.
Нетрудно понять, почему предварительная декларация class Node;
принадлежит в личном разделе, но как насчет typedef Iterator Node*;
? Это, вероятно, связано с моим непониманием typedef
ключевое слово, но почему это важно, какой спецификатор доступа применяется? я думал private
имеет больше смысла из-за видимости Node
учебный класс.
Это как-то связано с typedef
Является ли частью публичного интерфейса? Все ли typedef должны быть объявлены с public
видимость?
Редактировать:
Позвольте мне уточнить, я понимаю, что я могу остановить свой компилятор от жалоб, переместив typedef в public. Я не понимаю, почему это необходимо.
Вы можете просто сделать typedef name публичным именем. Попробуйте следующее
class List
{
public:
typedef class Node* Iterator;
Также учтите, что для обоих классов вы забыли поставить точки с запятой после закрывающих скобок. 🙂
List::Iterator
является закрытым, поэтому имя не может быть использовано, но тип может быть выведен
List l;
List::Iterator it = l.begin(); // Illegal
auto it = l.begin(); // legal
или же
template <typename IT>
void foo(IT it);
foo(l.begin()); // legal
Кстати, вы можете иметь List::Iterator
публично, и держать List::Node
частный.