Similarly, traversing over a linked list is also needed. While traversing you perform some
task on each node (e.g. print the content)
Note that printing is often added to the class (e.g. LinkedList) because it is a fixed and
expected task.
However, someone may need to traverse the list for whatever other reasons they want
(traverse and print twice the number in each node; maybe silly, but it's an example)
Although it is a good idea to add common, expected and mostly used tasks (such as
printing the list) as a member function to the class, we need more generic member
function to traverse the linked list in the main program
be aware that we cannot access private data members of the linked list class as we do in
the implementation of member functions
Goal
Often, we use what is called an iterator class to access a container class (e.g.
Linkedlist which contains the data)
e.g. In order to access the link list`s elements one by one from outside the class, what
can be done?
void Print (const LinkedList & list)
{
...
for ( ......... ; ................ ; .........)
cout << .........
cout << "size =" << list.length();
}
Iterators
In order to access a linkedlist`s nodes from outside the class, you need to do one of the
following:
1) Provide methods in the class to access individual elements but still this method may require
knowing or using some of class functions/structs
GetHead(), GetNext(), GetInfo() etc.
Friend Class
How to define a friend class (e.g. shapeFriend) to a class (e.g. shape):
class shape
{
public:
...
private:
...
friend class shapeFriend;
}
Friend declaration can be done anywhere in the class declaration (before
public and private, or under public or under private)
shape class grants friend status to shapeFriend (one way)
shapeFriend can acces private data and helper functions (defined in
private) of shape
but not vice versa
//copy constructor
void Init()
{
...
}
bool HasMore() const
{
...
}
// . . .
}
};
void Init()
{
...
}
bool HasMore() const
{
...
}
// . . .
}
myCurrent;
Reference is assigned to a
reference variable.
No copy constrcutor is invoked;
myList is another name for the
linked list (the parameter list) on
which the iterator will operate
}
----------------struct node {
int info;
node *next;
...
};
class LinkedList
{
friend class LinkedListIterator;
private:
};
public:
...
node * head;
int size;
12
};
public:
...
node * head;
int size;
13
int main()
{
LinkedList list1;
for (int k=0; k < 4; k++)
{
list1.addToBeginning(k+1);
}
4
Print(list1);
3
2
}
1
size = 4
What happens if you change head node of the list after binding to the
iterator (i.e. after creating the iterator object)?
Let us see the answer on the code
What about copy constructor and destructor for the iterator class?
We did not write and that was on purpose
We do not want deep copy here; the iterator object must not copy the
linked list
It operates on the existing list; thus the reference of the list is used.
Only shallow copy, thus default copy constructor is enough
Since we use the existing list in the iterator class, destructing the
iterator object is catastrophic.
Let's see the effect of having destructor on the code
dummy
NULL
The Iterator class of LinkStringSet is more or less similar to the other one
that we have seen, but there are some differences due to the design of
LinkStringSet. We will see them now.
LinkStringSet.h
class LinkStringSet
{
public:
// constructors
...
// accessors
int size() const;
...
// # elements in set
// mutators
...
friend class LinkStringSetIterator;
private:
struct Node
//node definition is embedded in class
{ string info;
Node * next;
...
};
...
Node * myFirst; //head of the list
int mySize;
//number of elements in the list
};
class LinkStringSetIterator
{
public:
LinkStringSetIterator (const LinkStringSet & list)
: myList(list), myCurrent(NULL)
{}
private:
const LinkStringSet & myList;
Alternative 1 (more usable, if you will frequently refer to Node):
myCurrent;
myCurrent;
Class LinkStringSet {
private:
struct Node {
string info;
Node * next;
}
Node * myFirst;
...
public:
...
friend class LinkStringSetIterator;
};
void Next()
{ myCurrent = myCurrent->next;
}
private:
//see previous slide
};
19
int main()
{
LinkStringSet a;
a.insert("apple");
a.insert("cherry");
cout << "a : ";
Print(a);
//cherry apple 2
}
LinkStringSet c;
c.insert("watermellon");
c.insert("apricot");
LinkStringSetIterator itr(c);
for (itr.Init(); itr.HasMore(); itr.Next())
{
itr.Current().append(" seed");
}
cout << "after update\nc : ";
Print(c);
What's output?
after update
c :
apricot seed
watermelon seed
---------- size = 2