-1

I'm studying C++ container and iterators and I'm trying to implement a rudimental linked list, just to get the hang of thi inner workings of iterators and container related stuff.

I defined a node class, along with a list class and the associated iterator, every class in its own header file,and each header is implemented in a separated code file.I didn't care about friend declarations,that was something I intended to cater to while trying to compile the project, but I stumbled upon something I failed to understand.

I defined several private fields in each class,and I expected the compiler to throw some errors at me during compilation, but it seems to be just fine with that! can you explain where am I wrong?? here's the code:

the node class:

template <typename T>
class mylist_node {

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

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

the list class:

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;

};

the list implementation code:

#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);
}

and the iterator class:

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 the mylist<T>::push_back() and the overloaded operators in mylist_iterator all access the private fields in mylist_node. I separatedly compile the source files without the compiler complaining about anything at all!

There must be something I didn't fully understand..

thanks!

Luca
  • 1,658
  • 4
  • 20
  • 41
  • if you downvote can you please explain why? thanks – Luca Aug 25 '15 at 11:26
  • 2
    You didn't ask a question. Did you expect the compiler to complain? If so, why? We can't correct your misunderstanding if you don't explain what you misunderstand. – David Schwartz Aug 25 '15 at 11:27
  • @DavidSchwartz if you read carefully, it's all in the question. I defined some private fields, and I subsequently access those fields in another class without the compiler complaining – Luca Aug 25 '15 at 11:29
  • 3
    Actually, I would expect the compilation to fails, because you use separate header and source files for a templated class, [which one usually don't do](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). That, together with your confusion, leads me to believe that you don't actually build with all the source files. – Some programmer dude Aug 25 '15 at 11:29
  • If it were me making the list class, I would add the struct node into the list class itself so that the list can access the members. Note that templated classes normally do not compile when doing .h and .cpp files; it is best to use just .h files for the entire implementation. – Joe Aug 25 '15 at 11:33
  • @DavidSchwartz for example in mylist.cpp mylist::push_back access the private next field in mylist_node – Luca Aug 25 '15 at 11:33
  • 2
    You probably never instantiate any of these classes. – David Schwartz Aug 25 '15 at 11:34
  • @DavidSchwartz if I build with all the source files and instantiate the class in a main() it doesn't find a match for push_back..??? – Luca Aug 25 '15 at 11:37
  • @Luca Please follow the link in my previous comment, it will help explain things. – Some programmer dude Aug 25 '15 at 11:37
  • 1
    @JoachimPileborg so if I rewrite the code and put all the implementations inline within the class definition it should instantiate the templates and find a match for push_back() and therefore complain about class access? – Luca Aug 25 '15 at 11:43
  • @Luca Yes that's correct. – Some programmer dude Aug 25 '15 at 11:49
  • @JoachimPileborg ok, now I wrote all the code in the same cpp file, but I can't make the mylist class a friend of mylist_node class, it says that mylist is not a template. But mylist is defined as a template and is defined later in the same code file. – Luca Aug 25 '15 at 12:17
  • @Luca `mylist` and `mylist` are two different things. You need to do e.g. `friend mylist;` – Some programmer dude Aug 25 '15 at 12:20
  • @JoachimPileborg yes,that's what I did. forward declaring `template class mylist;` seems to solve it. How's that? – Luca Aug 25 '15 at 12:21
  • @Luca In C++ everything must be declared before it's used, or the compiler wont know it exits. – Some programmer dude Aug 25 '15 at 12:31
  • @JoachimPileborg yes but I understand that doesn't apply to friend declarations (which are not themselves name declarations) because the compiler assumes that the definition happens somewhere in the class' enclosing scope. The problem doesn't seem to be the forward declaration (it doesn't complain if the type is a non-template) but the fact that it doesn't know it is a template. – Luca Aug 25 '15 at 12:34

1 Answers1

1

Compilers typically don't have a way to "sort of" compile code to figure out errors that would occur regardless of the type. They need to actually compile the code with a real type to detect most errors. If you never instantiate any of these classes, the real compilation won't take place.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278