Classes with dynamic members
‘Class’ matters! global local public class A { int x; public int x; void f(); } main() { A a; a.x = 0; a.f(); int x; void f() { x=10; } main() { x=0; f(); int x; void f() { x=10; } main() { x=0; f(); Unstructured with everything ‘global’ Structured with ‘local’ variables, ‘global’ functions Object-oriented with ‘global’ objects
Public or private? class A { int main() { public: A a; void f(); a.f(); cout << a.x << endl; cout << a.y << endl; // no!!! a.x = 1000; a.y = 10000; // no!!! } class A { public: void f(); int x; private: int y; } void A::f() { x=10; y=100; Global objects member functions (global? or public to objects) member variables (local or private to member functions)
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 static dynamic static
At least one pointer member (I.e. dynamic variable) classes At least one pointer member (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) = *(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; };
A constructor is called when: declare/define objects pass by value return by value X f(X x) { X a; return a; }
A function returning an object X f() { X x; return x; } ‘return x’ returns a temporay object ‘temp’ of class X by constructor (because x is a local object, and to be ‘destructed’ !)
Make an Abstract Data Type with ‘dynamic’ class One more example of ADT: integer linked list using class A class with dynamic objects: Copy constructor Destructor
linked lists: definition struct Node{ int data; Node* next; }; Node* head; bool listEmpty(Node* head) { } Node* addHead(Node* head, int newdata) { int getHead(Node* head) { Node* getRest(Node* head) { // void delHead(Node*& Head){ // }
Usage in ‘procedural way’: 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); 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; 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; cout << "Merged list is not palindrome" << endl; cout << "check the list again:" << endl; }
‘new’ member functions struct Node{ public: int data; Node* next; }; class listClass { listClass(); // constructor listClass(const listClass& list1); // copy constructor ~listClass(); // destructor bool empty() const; // boolean function void addHead(int newdata); // add to the head void delHead(); // delete the head int headElement() const; // access functions int length() const; // utility function void print() const; // output private: Node* head; ‘new’ member functions ‘old’ operations
Usage in ‘object way’: void main(){ listClass 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 } listClass N(L); N.print(); { 30 13 40 50 } listClass R; R.print(); { } if(R.empty()) cout << "List R empty" << endl; L.delHead(); 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
Some simple member functions: Implementation Some simple member functions: listClass::listClass() { head = NULL; } bool listClass::empty() const { if(head==NULL) return true; else return false; int listClass::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: listClass::listClass(const listClass& list1) { head = NULL; Node* cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } Call other member function!, so within ‘class’, still ‘procedural’.
Destructor: deallocation function listClass::~listClass() { Node* cur; while(head!=NULL){ cur = head; head = head->next; delete cur; }
Adding an element to the head: void listClass::addHead(int newdata) { Node* newPtr = new Node; newPtr->data = newdata; newPtr->next = head; head = newPtr; }
Deleting the head: void listClass::delHead() { if(head != NULL){ Node* cur = head; head = head->next; delete cur; }
Print the list: void listClass::print() const { cout << "{"; Node* cur = head; while(cur != NULL){ cout << cur->data << " "; cur = cur->next; } cout << "}" << endl;
Computing the number of elements of a given list: int listClass::length() const { int n=0; Node* cur = head; while(cur != NULL){ n++; cur = cur->next; } return n;