Classes with dynamic objects List as a dynamic
Classes with dynamic objects List as a (dynamic) class
‘Class’ matters! global local int x; void f() { x=10; } public class A { public int x; x=10; void f(); } } x=0; main() { f(); x=0; A a; f(); a. x = 0; main() { } a. f(); } }
Public or private? class A { public: int main() { void f(); A a; int x; a. f(); private: int y; cout << a. x << endl; } cout << a. y << endl; // no!!! void A: : f() { a. x = 1000; x=10; y=100; } a. y = 10000; // no!!! }
Abstract Data Type: public function, private data class A { int main() public: { A(); A a; int f(); cout << a. f(); // not a. x!!! private: A b(a); int x; A c; } c = a; // member-wise copy } A: : A() { x=0; } int A: : f() { return x; } 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; int* pa; a = 20; pa = new int; *pa = 20; a 20 static 20 pa static dynamic
classes Only static member variables At least one pointer variable (I. e. dynamic variable) class A { class B { public: B(); A(); B(const B& b); private: ~B(); int x; private: } int* px; } (Must) a defaut value constructor A() for initialisation (Must) a defaut value constructor for Creation by new + initialiation ‘copy constructor’ automatically privided (Must) redefine ‘copy constructor’ No destructor (Must) the destructor ‘assignment’ automatically provided (Must) redefine ‘assignment’ (do later)
class B { B: : B() { px = new int; public: *px = 0; B(); B(const B& b); } ~B(); private: B: : B(const B& b) { px = new int; int* px; (*px) = *(b. px); } } B: : ~B() { delete 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; };
Example of a (dynamic) class: linked list class
linked lists: definition struct Node{ int data; Node* next; }; bool list. Empty(Node. Ptr head) { } int get. Head(Node. Ptr head) { typedef Node* Node. Ptr; Node. Ptr head; } Node. Ptr get. Rest(Node. Ptr head) { } Node. Ptr add. Head(Node. Ptr head, int newdata) { } void del. Head(Node. Ptr& Head){ }
Usage: void main(){ Node. Ptr Head 1=NULL, Head 2 = NULL, Head; add. Head(Head 1, 50); add. Head(Head 1, 40); add. Head(Head 1, 30); add. Head(Head 1, 20); cout << "List 1: " << endl; Display. List(Head 1); cout << "Length of Head 1 list: " << length(Head 1) << endl; cout << "Recursive length of Head 1 list: " << length. Rec(Head 1) << endl; if(is. Palindrome(Head 1)) cout << "Head 1 list is palindrome" << endl; else cout << "Head 1 list is not palindrome" << endl; add. Head(Head 2, 25); add. Head(Head 2, 35); add. Head(Head 2, 45); add. Head(Head 2, 35); add. Head(Head 2, 25); cout << "List 2: " << endl; Display. List(Head 2); cout << "Length of Head 2 list: " << length(Head 2) << endl; cout << "Recursive length of Head 2 list: " << length. Rec(Head 2) << endl; if(is. Palindrome(Head 2)) cout << "Head 2 list is palindrome" << endl; else cout << "Head 2 list is not palindrome" << endl; Head = merge. Lists(Head 1, Head 2); cout << "Merged List: " << endl; Display. List(Head); cout << "Length of Merged list: " << length(Head) << endl; cout << "Recursive length of Merged list: " << length. Rec(Head) << endl; if(is. Palindrome. Rec(Head)) cout << "Merged list is palindrome" << endl; else cout << "Merged list is not palindrome" << endl; cout << "check the list again: " << endl; Display. List(Head);
Make an Abstract Data Type l l One more example of ADT: l integer linked list using class A class with dynamic objects: l Copy constructor l Destructor
struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; ‘new’ member functions class list { public: list(); // constructor list(const list& list 1); // copy constructor ~list(); // destructor bool empty() const; int head. Element() const; // boolean function // access functions void add. Head(int newdata); void delete. Head(); // add to the head // delete the head int length() const; void print() const; private: Nodeptr head; }; // utility function // output ‘old’ operations
How to use it void main(){ list L; L. print(); L. add. Head(30); L. print(); L. add. Head(13); L. print(); L. add. Head(40); L. print(); L. add. Head(50); L. print(); list N(L); N. print(); } // constructor called automatically here for L { } { 30 } { 13 30 } { 40 13 30 } { 50 40 13 30 } list R; R. print(); { } if(R. empty()) cout << "List R empty" << endl; L. delete. Head(); L. print(); { 40 13 30 } L. delete. Head(); 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. head. Element() << 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: : head. Element() 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& list 1) { head = NULL; Nodeptr cur = list 1. head; while(cur != NULL) { // add. End(cur->data); add. Head(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: : add. Head(int newdata){ Nodeptr new. Ptr = new Node; new. Ptr->data = newdata; new. Ptr->next = head; head = new. Ptr; }
Deleting the head: void list: : delete. Head(){ 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& list 1); // copy constructor const list& operator=(const list& list 1); // assigment, l = l 1; ~list(); // destructor bool empty() const; int head() const; list remaining() const; // boolean function // access functions // the list with the head removed void insert(int d); void delete(int d); // insertion // deletion int length() const; void print() const; private: Nodeptr head; // utility function // Interface functions }; An almost ideal list class
copy constructor: list: : list(const list. Class& list 1) { head = NULL; Nodeptr cur = list 1. head; while(cur != NULL) { // add. End(cur->data); add. Head(cur->data); // inverse list order cur = cur->next; } Operator assignment, ‘deep copy’ } Const list& operator=(const list& list 1) { if (this != &list 1) { head = NULL; Nodeptr cur = list 1. head; while(cur != NULL) { // add. End(cur->data); add. Head(cur->data); // inverse list order cur = cur->next; } return *this; } Delete[] head; Big three: copy constructor, operator=, destructor
Usage difference list l 1, l 2; node* head 1, head 2; head 1 = NULL; head 2 = NULL l 1. add. End(5); add. End(head 1, 5); list l 3(l 1); node* head 3 = NULL; l 3 = l 2; copylist(head 1, head 3); head 3 = head 2;
- Slides: 24