2015-08-25 2 views
-1

Я изучаю контейнер и итераторы C++, и я пытаюсь реализовать рудиментарный связанный список, просто чтобы получить зависание внутренней работы итераторов и связанных с контейнерами вещей.инкапсуляции и классы друзей в C++

Я определил класс узла, класс списка и связанный с ним итератор, каждый класс в своем собственном файле заголовка, и каждый заголовок реализован в отдельном файле кода. Мне не нравились объявления друзей, это было то, что я собирался удовлетворить, пытаясь скомпилировать проект, но я наткнулся на то, что я не понял.

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

класс узла:

template <typename T> 
class mylist_node { 

    public: 
    mylist_node(const T&,mylist_node<T>*); 
    ~mylist_node() {} 

    private: 
    T element; 
    mylist_node<T> *next; 
}; 

класс список:

template <typename T> 
class mylist { 

    public: 
    typedef mylist_iterator<T> iterator; 
    mylist() : head(NULL),tail(NULL) {} 
    void push_back(const T&); 
    bool empty(); 
    iterator begin(); 
    iterator end(); 

    private: 
    mylist_node<T> *head,*tail; 

}; 

код реализации списка:

#include <cstdlib> 
#include "mylist_node.h" 
#include "mylist_iterator.h" 
#include "mylist.h" 

template <typename T> 
void mylist<T>::push_back(const T& element) 
{ 
    //dynamically allocated object so it is not destroyed on function exit 
    mylist_node<T> *new_node=new mylist_node<T>(element,NULL); 
    if (head==NULL)     
    head=new_node; 
    else 
    tail->next=new_node; 
    tail=new_node;  
} 

template <typename T> 
bool mylist<T>::empty() 
{ 
    return head==tail; 
} 

template <typename T> 
typename mylist<T>::iterator mylist<T>::begin() 
{ 
    return mylist_iterator<T>(head); 
} 

template <typename T> 
typename mylist<T>::iterator mylist<T>::end() 
{ 
    return mylist_iterator<T>(NULL); 
} 

и класс итератора:

template <typename T> 
class mylist_iterator { 

    public: 
    T &operator*(); 
    const mylist_iterator<T> &operator++(); 
    bool operator!=(const mylist_iterator<T>&); 

    private: 
    mylist_iterator(mylist_node<T> *pointee) : pointee(pointee) {} 
    mylist_node<T> *pointee; 

}; 

obiouvsly mylist<T>::push_back() и перегруженные операторы в mylist_iterator все доступ к закрытым полям в mylist_node. Я отдельно компилирую исходные файлы без компилятора, жалующегося на что-нибудь вообще!

Там должно быть что-то я не совсем понимаю ..

спасибо!

+0

если вы не можете объяснить, почему? спасибо – Luca

+2

Вы не задавали вопрос. Вы ожидали, что компилятор будет жаловаться? Если да, то почему? Мы не можем исправить ваше недоразумение, если вы не объясните, что вы неправильно поняли. –

+0

@DavidSchwartz, если вы внимательно прочитаете, все дело в вопросе. Я определил некоторые частные поля и впоследствии получил доступ к этим полям в другом классе без жалобы компилятора – Luca

ответ

1

У компиляторов обычно нет способа «сортировать» компилируемый код, чтобы определить ошибки, которые произойдут независимо от типа. Они должны действительно скомпилировать код с реальным типом, чтобы обнаружить большинство ошибок. Если вы никогда не создаете экземпляр какого-либо из этих классов, реальная компиляция не состоится.

+1

Но вам также нужно вызвать/создать экземпляр определенной функции-члена, не так ли? – LogicStuff

+1

http://en.cppreference.com/w/cpp/language/class_template#Explicit_instantiation –

Смежные вопросы