240 likes | 389 Vues
List as a (dynamic) class. Classes with dynamic objects. ‘Class’ matters!. global. local. public. class A { public int x; void f(); } main() { A a; a.x = 0; a.f(); }. int x; void f() { int x; x=10; } main() { x=0; f(); }. int x; void f() { x=10; } main() {
E N D
List as a (dynamic) class Classes with dynamic objects
‘Class’ matters! global local public class A { public int x; void f(); } main() { A a; a.x = 0; a.f(); } int x; void f() { int x; x=10; } main() { x=0; f(); } int x; void f() { x=10; } main() { x=0; f(); }
Public or private? class A { public: void f(); int x; private: int y; } void A::f() { x=10; y=100; } int main() { A a; a.f(); cout << a.x << endl; cout << a.y << endl; // no!!! a.x = 1000; a.y = 10000; // no!!! }
Abstract Data Type: public function, private data class A { public: A(); int f(); private: int x; } A::A() { x=0; } int A::f() { return x; } int main() { A a; cout << a.f(); // not a.x!!! A b(a); A c; c = a; // member-wise copy } Objects are calling member funtions (public interface) Member functions are using member variables (private data) Objects are not directly dependent on implementation (private data)
Static and dynamic Static variables (objects) Dynamic variables (objects) A (direct) named memory location A static part (pointer) + (indirect) nameless memory location (dynamic part) int a; a = 20; int* pa; pa = new int; *pa = 20; 20 20 a pa dynamic static static
classes At least one pointer variable (I.e. dynamic variable) Only static member variables class B { public: B(); B(const B& b); ~B(); private: int* px; } class A { public: A(); private: int x; } (Must) a defaut value constructor A() for ‘copy constructor’ automatically privided No destructor ‘assignment’ automatically provided (Must) a defaut value constructor for (Must) redefine ‘copy constructor’ (Must) the destructor (Must) redefine ‘assignment’ (do later) Creation by new + initialiation initialisation
B::B() { px = new int; *px = 0; } B::B(const B& b) { px = new int; (*px) = *(b.px); } B::~B() { delete px; } class B { public: B(); B(const B& b); ~B(); private: int* px; }
Automatic behavior of constructors/destructor All constructors/destructor have automatic behavior, they are called ‘implicitly’!!! (that’s why they have standard names!) Constructors are called when creating variables and other occasions: A a; // implicitly call the default value constructor A::A(); A b(a); // implicitly call the copy constructor A::A(const A& a); Destructors are called when the variables go out of scope void somefunction() { B b; };
linked lists: definition struct Node{ int data; Node* next; }; typedef Node* NodePtr; NodePtr head; bool listEmpty(NodePtr head) { } int getHead(NodePtr head) { } NodePtr getRest(NodePtr head) { } NodePtr addHead(NodePtr head, int newdata) { } void delHead(NodePtr& Head){ }
Usage: void main(){ NodePtr Head1=NULL, Head2 = NULL, Head; addHead(Head1, 50); addHead(Head1, 40); addHead(Head1, 30); addHead(Head1, 20); cout << "List 1: " << endl; DisplayList(Head1); cout << "Length of Head1 list: " << length(Head1) << endl; cout << "Recursive length of Head1 list: " << lengthRec(Head1) << endl; if(isPalindrome(Head1)) cout << "Head1 list is palindrome" << endl; else cout << "Head1 list is not palindrome" << endl; addHead(Head2, 25); addHead(Head2, 35); addHead(Head2, 45); addHead(Head2, 35); addHead(Head2, 25); cout << "List 2: " << endl; DisplayList(Head2); cout << "Length of Head2 list: " << length(Head2) << endl; cout << "Recursive length of Head2 list: " << lengthRec(Head2) << endl; if(isPalindrome(Head2)) cout << "Head2 list is palindrome" << endl; else cout << "Head2 list is not palindrome" << endl; Head = mergeLists(Head1, Head2); cout << "Merged List: " << endl; DisplayList(Head); cout << "Length of Merged list: " << length(Head) << endl; cout << "Recursive length of Merged list: " << lengthRec(Head) << endl; if(isPalindromeRec(Head)) cout << "Merged list is palindrome" << endl; else cout << "Merged list is not palindrome" << endl; cout << "check the list again:" << endl; DisplayList(Head); }
Make an Abstract Data Type • One more example of ADT: • integer linked list using class • A class with dynamic objects: • Copy constructor • Destructor
‘new’ member functions struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; class list { public: list(); // constructor list(const list& list1); // copy constructor ~list(); // destructor bool empty() const; // boolean function int headElement() const; // access functions void addHead(int newdata); // add to the head void deleteHead(); // delete the head int length() const; // utility function void print() const; // output private: Nodeptr head; }; ‘old’ operations
How to use it void main(){ list L; // constructor called automatically here for L L.print(); { } L.addHead(30); L.print(); { 30 } L.addHead(13); L.print(); { 13 30 } L.addHead(40); L.print(); { 40 13 30 } L.addHead(50); L.print(); { 50 40 13 30 } list N(L); N.print(); { 50 40 13 30 } list R; R.print(); { } if(R.empty()) cout << "List R empty" << endl; L.deleteHead(); L.print(); { 40 13 30 } L.deleteHead(); L.print(); { 13 30 } if(L.empty()) cout << "List L empty" << endl; else{ cout << "List L contains " << L.length() << " nodes" << endl; cout << "Head element of list L is: " << L.headElement() << endl; } } // destructor called automatically here for L
Implementation Some simple member functions: list::list(){ head = NULL; } bool list::empty() const{ if(head==NULL) return true; else return false; } int list::headElement() const { if(head != NULL) return head->data; else{ cout << "error: trying to find head of empty list" << endl; exit(1); } }
(explicitly defined) copy constructor: list::list(const list& list1) { head = NULL; Nodeptr cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } }
Destructor: deallocation function list::~list(){ Nodeptr cur; while(head!=NULL){ cur = head; head = head->next; delete cur; } }
Adding an element to the head: void list::addHead(int newdata){ Nodeptr newPtr = new Node; newPtr->data = newdata; newPtr->next = head; head = newPtr; }
Deleting the head: void list::deleteHead(){ if(head != NULL){ Nodeptr cur = head; head = head->next; delete cur; } }
Print the list: void list::print() const{ cout << "{"; Nodeptr cur = head; while(cur != NULL){ cout << cur->data << " "; cur = cur->next; } cout << "}" << endl; }
Computing the number of elements of a given list: int list::length() const{ int n=0; Nodeptr cur = head; while(cur != NULL){ n++; cur = cur->next; } return n; }
struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; class list { public: list(); // constructor list(const list& list1); // copy constructor const list& operator=(const list& list1); // assigment, l = l1; ~list(); // destructor bool empty() const; // boolean function int head() const; // access functions list remaining() const; // the list with the head removed void insert(int d); // insertion void delete(int d); // deletion int length() const; // utility function void print() const; // private: Nodeptr head; }; Interface functions An almost ideal list class
copy constructor: list::list(const listClass& list1) { head = NULL; Nodeptr cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } } Operator assignment, ‘deep copy’ Const list& operator=(const list& list1) { if (this != &list1) { head = NULL; Nodeptr cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } return *this; } Delete[] head; Big three: copy constructor, operator=, destructor
Usage difference node* head1, head2; head1 = NULL; head2 = NULL addEnd(head1,5); node* head3 = NULL; copylist(head1, head3); head3 = head2; list l1, l2; l1.addEnd(5); list l3(l1); l3 = l2;