My assignment is to make a class that acts like a standard library List. I am unable to get the iterator to work properly, because it must access the tail of the linked list when decrementing from the end. Here is a section of my header file:

typedef int T;//for now; eventually will be templated
class list;//**forward declaration, doesn't let other classes know about _tail.**
class Node
{
    //this works fine; class definition removed to make post shorter
};
class list_iterator
{
    private:
        Node* _node;
        list* _list;
    public:
        //constructor
        list_iterator& operator--(){_node=_node?(_node->_prev):(_list->_tail);return *this;}
        //some other declarations
};
class list
{
    friend class list_iterator;
    private:
        Node/*<T>*/ *_head,***_tail**;
        int _size;
    public:
        typedef list_iterator iterator;
        //some constructors and other method declarations
        iterator begin() const {iterator it(_head);return it;}
        iterator end() const {iterator it(0);return it;}
        //more method declarations
};

I tried to bold the important parts, but it is just surrounding them with asterisks. NOTE: Most of the member functions are defined in the cpp file; they all happen to be removed for a short post.

有帮助吗?

解决方案

You just need to move the method definition of operator-- out of the class and put it after list (or in the source file (probably a better idea. Leave the header file for declarations)).

Note: Leave the declaration inside list_iterator

class list_iterator
{
    /* STUFF */
    list_iterator& operator--();
 };
class list
{ 
     /*  STUFF */ 
};

// Now list_iterator::operator-- can see all the members of list.
list_iterator& list_iterator::operator--()
{
    _node=_node?(_node->_prev):(_list->_tail);
    return *this;
}

Unlike what some other answers suggest. Friendship does NOT break encapsulation. In fact in increases encapsulation (when done correctly) by making the friend part of the classes interface. It does however tightly bind the friend to the class.

This is exactly what you want for iterators. For the iterator to work efficiently it needs to know the internals of the class so it is usually a friend (or an internal class). It increases the usability of the class without exposing the internal workings of the class at the cost that it tightly couples the iterator to the class (so if you change the class you will need to change the implementation of the iterator (but this is not unexpected)).

其他提示

By far the easiest way is to nest the iterator inside the list class:

class list { 
    Node *head, *tail;

    class iterator {
        Node *node;
        list *list;
    // ...
    };
};

If you don't want to do that, you'll need to split the implementations of both list and list_iterator into two pieces: first a class definition that only declares the member functions, then implementations of the member functions:

class list;

class list_iterator { 
    // ...
    Node *n;
    list *l;
};

class list {
    // ...
    friend class list_iterator;
};

inline list_iterator& list_iterator::operator--(){
    _node=_node?(_node->_prev):(_list->_tail);
    return *this;
}

This way, list has been declared by the time you define the list * in the definition of list_iterator. Then _tail has been defined in list, then you have the code in list_iterator::operator-- that actually needs to use list::_tail..

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top