1 / 22

Classes : Advanced Topics

Classes : Advanced Topics. iterators & friend classes Tapestry pp. 614-620. Overview & Purpose. When we write a container class , such as LinkedList or linkstrinset classes, we normally add all functionality that we think would be useful by the users of the class

ddonnie
Télécharger la présentation

Classes : Advanced Topics

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Classes: Advanced Topics iterators & friend classes Tapestry pp. 614-620

  2. Overview & Purpose When we write a container class, such as LinkedList or linkstrinset classes, we normally add all functionality that we think would be useful by the users of the class • For example, AddInOrder because people may want to use a linked list as an ordered list • or may be just an Add function, etc. 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 just 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 functions 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 This functionality is typically provided as an iterator class, associated with the corresponding container class. In this slide set, we will see how an iterator class may be written, for the LinkedList class. • These slides are also useful in strengthening/understanding of class member variables and reference variables / reference return.

  3. 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(); }

  4. 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. 2) Write an associated iterator class: • that can access the private members of the LinkedList class without giving client code the right to access private data • a bit more complex but preferable • defined asFriend class to the main container class (in our example LinkedList class) void Print(const LinkedList & list) { LinkedListIterator iter (list); for (iter.Init(); iter.hasMore(); iter.Next()) cout << iter.Current(); cout << "size =" << list.length(); }

  5. Iterators & Friend Classes We will show the iterator class concepts over two example cases. First we will extend previously developed LinkedList class with integer container so that it now includes a friend iterator class. Later we will go over the iterator class of Tapestry's linkstringset class. First of all, the container class for which we are writing an iterator class, needs to declare the iterator class as friend. The friend class is not limited to iterators only. Any two class declarations that needto be separate, buttightly coupled can be friends.

  6. FriendClass 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 unless reverse friend declaration is made

  7. LinkedListClassDeclaration (.h file) //Declaration of struct node comes here class LinkedList { friend class LinkedListIterator; private: node * head; int size; public: LinkedList (); LinkedList (const LinkedList &); //copy constructor ~LinkedList (); //destructor void printList() const; void addToBeginning(int n); void deleteList (); int length() const; //returns # of elements in the list const LinkedList & LinkedList::operator = (const LinkedList & rhs); node * createClone () const; };

  8. CompletingtheIteratorClass class LinkedListIterator { public: //constructorcomeshere void Init() { . . . } boolHasMore() const//notetheuse of const { . . . } intCurrent() const { . . . } void Next() { . . . } private: //what do weneedtohave as data members? }; How should the iterator class be defined, so as to work as follows? void Print(const LinkedList & list) { LinkedListIterator iter (list); for (iter.Init(); iter.hasMore(); iter.Next()) cout << iter.Current(); // . . . }

  9. CompletingtheIteratorClass class LinkedListIterator { public: //constructorcomeshere void Init() { . . . } boolHasMore() const//notetheuse of const { . . . } intCurrent() const { . . . } void Next() { . . . } private: //what do weneedtohave as data members? //youneedtoaccessthelist //youneedtohave a pointeroverthelist }; How should the iterator class be defined, so as to work as follows? void Print(const LinkedList & list) { LinkedListIterator iter (list); for (iter.Init(); iter.hasMore(); iter.Next()) cout << iter.Current(); // . . . }

  10. Private Data Members of theIteratorClass class LinkedListIterator { public: . . . . private: const LinkedList& myList; // to access the linked list //reference variable will refer to the linked list which is defined outside, //as opposed to making a local copy of it. //it is const so that it can matchconst parameters (see Print function) //and also so that we are sure not to change anything node * myCurrent; // to access the next node of the linked list };

  11. ConstructorfortheIteratorClass Here the complication is how the iterator should be constructed, so that it can access the linkedlist’s private data Constructor and member functions are declared and defined together here • Not a rule though; you could have a separate implementation file class LinkedListIterator { public: LinkedListIterator(const LinkedList & list) : myList(list), myCurrent(NULL) { } . . . //more functions will come private: const LinkedList & myList; node * myCurrent; }; Reference is assignedto a referencevariable. No copyconstrcutor is invoked; myList is another name forthelinkedlist (theparameterlist) on whichtheiteratorwilloperate

  12. CompletingtheIteratorClass • Howshouldtheiteratorclass be defined, • so as towork as follows? • void Print(const LinkedList & list) • { • LinkedListIterator iter (list); • for (iter.Init(); iter.hasMore(); iter.Next()) • cout << iter.Current(); • // . . . • } • - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - • structnode { • intinfo; • node *next; • . . . • }; • classLinkedList • { • friendclassLinkedListIterator; • private: • node * head; • int size; • public: • . . . • }; class LinkedListIterator { public: LinkedListIterator(const LinkedList & list) : myList(list), myCurrent(NULL) { } void Init() { . . . } bool HasMore() const { . . . } int Current() const { . . . } void Next() { . . . } private: …//see previous slides }; InitializetheiteratorsothatmyCurrentshowsthehead of thelist Arewe at theend of thelist? Theinfofield of thenodethatmyCurrentpoints Advancetothenextnode.

  13. CompletingtheIteratorClass • Howshouldtheiteratorclass be defined, • so as towork as follows? • void Print(const LinkedList & list) • { • LinkedListIterator iter (list); • for (iter.Init(); iter.hasMore(); iter.Next()) • cout << iter.Current(); • // . . . • } • - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - • structnode { • intinfo; • node *next; • . . . • }; • classLinkedList • { • friendclassLinkedListIterator; • private: • node * head; • int size; • public: • . . . • }; class LinkedListIterator { public: LinkedListIterator(const LinkedList & list) : myList(list), myCurrent(NULL) { } void Init() { myCurrent = myList.head; // mycurrent points to first node } bool HasMore() const { return (myCurrent != NULL); } int Current() const { return myCurrent->info; } void Next() { myCurrent = myCurrent->next; } private: …//see previous slides };

  14. Where to Use the Iterator Class //free function void Print(const LinkedList & list) { LinkedListIterator iter (list); for (iter.Init(); iter.hasMore(); iter.Next()) cout << iter.Current()<< endl; cout << "size = " << list.length() << endl; } int main() { LinkedList list1; for (int k=0; k < 4; k++) { list1.addToBeginning(k+1); } Print(list1); } • LinkedListIterator(const LinkedList& list) • : myList(list), myCurrent(NULL) • { } Constructor of theiteratorclass is called. iter.myListreferstolistsothatiterobject is boundtothelinkedlistobjectlist In general, an iteratorobjectis bound to a particular container (e.g. linkedlist) when the iterator is constructed! 4 3 2 1 size = 4 SeeLinkedListIterator.h and .cpp, andLinkedListIteratordemo.cpp fordetails

  15. SomeIssuesabouttheIteratorClass Do we have another .h file for the iterator class? • We could have, but preferred to have both LinkedList and its iterator class in the same .h file 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 How can you change the value in a node using iterator? • 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

  16. IteratorClassforLinkStringSet LinkedStringSet is a Tapestry Class for a linked list with string container. It works in set manner; that is, the insertion function first check if an element exists in the list. If so,it does not add. If not, adds. The implementation uses dummy node. The dummy node is the first node of the list and it does not contain real data. The first real node is the next of dummy node. The use of dummy node makes sure that the list is never empty (head does not point to 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. list object myFirst mySize dummy ab c NULL 3

  17. LinkStringSet.h classLinkStringSet { public: // constructors . . . // accessors int size() const; // # elements in set . . . // mutators . . . friendclassLinkStringSetIterator; private: structNode//nodedefinition is embedded in class { stringinfo; Node * next; . . . }; . . . Node * myFirst; //head of thelist intmySize; //number of elements in thelist };

  18. ConstructorandPrivate Data MembersfortheIteratorClass Having the node definition in the LinkStringSet class slightly changes the private data members as compared to the case of other LinkedList class iterator. 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): typedef LinkStringSet::Node Node;//define a new type name // based on an already defined type Node * myCurrent; //pointer to a linklist node Alternative 2 (more clear): LinkStringSet::Node * myCurrent; //refer to LinkList class’s node type, rather // than defining a new type };

  19. CompletingtheIteratorClass class LinkStringSetIterator { public: LinkStringSetIterator(const LinkStringSet & list) : myList(list), myCurrent(NULL) { } void Init() { myCurrent = myList.myFirst->next; // mycurrent points to first real node } bool HasMore() const { return (myCurrent != NULL); } string Current() const { return myCurrent->info; } void Next() { myCurrent = myCurrent->next; } private: …//see previous slide }; class LinkStringSet { private: struct Node { string info; Node * next; } Node * myFirst; //points to dummy header. . . public: . . . friend class LinkStringSetIterator; };

  20. UsingtheLinkStringSetIterator Class Not different than the other Iterator class void Print(const LinkStringSet & list) { LinkStringSetIterator it (list); for (it.Init(); it.hasMore(); it.Next()) cout << it.Current(); cout << ``size =`` << list.Size(); } int main() { LinkStringSet a; a.insert("apple"); a.insert("cherry"); cout << "a : "; Print(a); //cherry apple 2 } Seelinkedstringset.h and .cpp, andlinksetdemo.cpp fordetails

  21. UsingtheLinkStringSetIterator Class - 2 • Why it did not work out? • string Current() const • { return myCurrent->info; • } • Current returns a copy due to return type string. • What's updated is this copy, not the list's element. • How can we solve it? See next slide for one solution. Updating the values stored in the nodes – e.g. append " seed" the end of the info field of each node in the list LinkStringSet c; c.insert("watermelon"); c.insert("apricot"); LinkStringSetIteratoritr(c); for(itr.Init(); itr.HasMore(); itr.Next()) { itr.Current().append(" seed"); } cout << "afterupdate\nc : "; Print(c); What's output? after update c : apricot watermelon ---------- size = 2 Seelinkedstringset.h and .cpp, andlinksetdemo.cpp fordetails

  22. UsingtheLinkStringSetIterator Class - 3 • Solution: Let the Current () function return a reference to the current node's string info • string & Current() const • { return myCurrent->info; • } • When the return value of Current() is updated the current list element is updated. 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? Seelinkedstringset.h and .cpp, andlinksetdemo.cpp fordetails after update c : apricot seed watermelon seed ---------- size = 2

More Related