2016-02-22 4 views
2

Так обычно я следовать соглашению о размещении своих функций государственных членов, прежде чем мои личные атрибуты, какКогда заказывается публичный/частный не выбор стиля?

class SomeClass { 
public: 
    void amazingMethod(); 
private: 
    int fantasticAttribute; 
}; 

Так что пользователь (включая меня) хочет видеть первым в классе вещи я могу использовать. Однако недавний мой проект ввел некоторые настоящие странности.

template<typename T> 
class LinkedList { 
public: 
    class LinkedListIterator { 
    public: 
     LinkedListIterator(Node* node) : node(node) {} 
     LinkedListIterator& operator++() { 
      if (node != nullptr) { 
       node = node->next; 
      } 
     } 
    private: 
     Node* node; 
    }; 
    LinkedListIterator begin() { 
     return LinkedListIterator(head); 
    } 
private: 
    struct Node { 
     Node* next; 
    }; 
    Node* head; 
}; 

Этот код не компилирует в Visual Studio 2015, сообщив, что Node не определен, когда LinkedListIterator пытается использовать его. Но что странно, что если я флип LinkedList так он объявлен как

template <typename T> 
class LinkedList { 
private: 
    //everything that was in private before 
public: 
    //everything that was in public before 
}; 

Все компилируется правильно! Это просто причуда Visual Studio? Я предполагаю, что это связано с тем, что это класс шаблонов, но я не знаю.

Как я узнаю, когда я должен созерцательно уйти от объявления публичных членов (как следует из большинства конвенций)? Когда это становится не просто выбором стиля?

+1

имеет смысл для меня - типа «Узел» еще не был замечен. Я уверен, что адвокат языка будет вместе, чтобы дать вам главу и стих стандарта, который ее описывает ;-) – John3136

+1

Я не знаю, но я думаю, вы всегда можете просто перейти к узлу структуры; над декларацией итератора. поскольку указатель на эту структуру используется как параметр для публичной функции в открытом классе, нет причин, чтобы строка не могла быть общедоступной? – matt

+1

В качестве части решения проблем обычно рекомендуется сначала попытаться опровергнуть вашу гипотезу. Ваша гипотеза заключается в том, что она связана с 'private/public' ... поэтому просто сделайте все« public »- вы увидите, что один компилятор компиляции, а другой - нет. – Barry

ответ

3

Он не имеет ничего общего с типами доступа. Он имеет все, что связано с LinkListIterator, пытаясь использовать тот тип, который компилятор еще не видел.

Однако, поскольку класс итератора использует только указатель на тип Node, достаточно указать прямое объявление. Следующий код добавляет опережающее объявление и компилирует просто отлично:

template<typename T> 
class LinkedList { 
private: 
    struct Node; // Private forward declaration of the private class 

public: 
    class LinkedListIterator { 
    public: 
     LinkedListIterator(Node* node) : node(node) {} 
     LinkedListIterator& operator++() { 
      if (node != nullptr) { 
       node = node->next; 
      } 
     } 
    private: 
     Node* node; 
    }; 
    LinkedListIterator begin() { 
     return LinkedListIterator(head); 
    } 
private: 
    struct Node { 
     Node* next; 
    }; 
    Node* head; 
}; 

int main() 
{ 
    return 0; 
} 

Live Example

1

Это не имеет ничего общего с государственными и частными как таковыми. Это связано с тем, был ли определен Node в точке использования.

0

Если вы хотите, чтобы объявить открытые член первыми, переделку своих определений:

template<typename T> 
class LinkedList { 
public: 
    class LinkedListIterator; 
    LinkedListIterator begin(); 
private: 
    struct Node; 
    Node* head; 
}; 

template<typename T> 
struct LinkedList<T>::Node { 
    Node* next; 
}; 

template<typename T> 
class LinkedList<T>::LinkedListIterator { 
public: 
    LinkedListIterator(Node* node); 
    LinkedListIterator& operator++(); 
private: 
    Node* node; 
}; 

template<typename T> 
LinkedList<T>::LinkedListIterator::LinkedListIterator(Node* node) : node(node) {} 

template<typename T> 
typename LinkedList<T>::LinkedListIterator& LinkedList<T>::LinkedListIterator::operator++() { 
    if (node != nullptr) { 
     node = node->next; 
    } 
    return *this; 
} 

template<typename T> 
typename LinkedList<T>::LinkedListIterator LinkedList<T>::begin() { 
    return LinkedListIterator(head); 
}