500 likes | 646 Views
Lecture 15. C++ Multiple Inheritance Operator overloading Templates Pointers Dynamic memory allocation Standard Template Library Containers Iterators Algorithms. Lecture Schedule. Mon 5/11/01 (Bjoern) VisualWorks/Smalltalk Mon 12/11/01 (Frank) C++ Game playing (lab4)
E N D
Lecture 15 • C++ • Multiple Inheritance • Operator overloading • Templates • Pointers • Dynamic memory allocation • Standard Template Library • Containers • Iterators • Algorithms
Lecture Schedule • Mon 5/11/01 (Bjoern) • VisualWorks/Smalltalk • Mon 12/11/01 (Frank) • C++ • Game playing (lab4) • Course evaluation • Tue 20/11/01 (Bjoern) • VisualWorks/Smalltalk
Inheritance subclass super class Feature A Feature A Feature B Feature B Feature C Feature D
Inheritance class Date { public: // visible outside class scope int Year(); … protected: // visible to sub-classes but hidden from rest of the world int day, month, year; }; class DateTime : public Date { public: int Hours(); … private: // only visible to class DateTime int hours, minutes };
Multiple Inheritance subclass base class A Feature A Feature A Feature B Feature B Feature C base class B Feature D Feature C Feature D
Multiple Inheritance class Date { public: int Year(); private: int day, month, year; }; class Time { public: int Hours(); private: int hours, minutes; };
Multiple Inheritance class DateTime : public Date, public Time { public: DateTime(int d, int m, int y, int h, int mi); … }; DateTime::DateTime(int d, int m, int y, int h, int mi) : Date(d,m,y), Time(h, mi) { }
Ambiguity in Multiple Inheritance class Date { void add(int days); }; class Time { void add(int minutes); }; Class DateTime : public Date, public Time { }; DateTime dt(13,2,1998,23,10); dt.add(3); // ambiguous -- will not compile dt.Date::add(4); // uses add of class Date dt.Time::add(5); // uses add of class Time
Ambiguity in Multiple Inheritance class A { public: void F(); }; class B : public A { …}; class C : public A { …}; class D : public B, public C {}; D d; d.F(); // ambiguous - won´t compile class A diamond shaped inheritance tree class B class C class D
Overloading Operator • Operator overloading is a useful feature of object oriented programming • Operator overloading allows it to give normal C++ operators such as +,-,==,< additional meanings • It makes statements more intuitive and readable for example: Date d1(12,3,1989); Date d2; d2.add_days(d1,45); // can be written with the + operator as d2=d1+45;
Operator Overloading • The name of an operator function is the keyword operator followed by the operator itself. class complex { double re, im; // re and im part of a complex number public: complex (double r, double i) : re(r), im(i) {}; //constructor complex operator+(complex c); // operator function }; complex c1(2.2,3.0); // instantiate complex c1 complex c2(1.0,-4.5); // instantiate complex c2 complex c3=c1+c2; // shorthand notation for c1 + c2 complex c4=c1.operator+(c2); // explicit call
Overloading Unary Operators class Date { Date& operator++(); // prefix increment operator } Date& Date::operator++ () { if (++day > days_in_month()) { day=1; if (++month > 12) { month=1; year++; } } return *this; } Date d1(31,12,1999); ++d1; // results in 1.1.2000
Overloading Unary Operators class Date { Date operator++(int); // postfix increment operator }; Date Date::operator++ (int) { Date old(*this); if (++day > days_in_month()) { day=1; if (++month > 12) { month=1; year++; } } return old; } Date d1(31,12,1999); Date d2; d2=d1++; // assigns 31.12.01 to d2, d1 becomes 1.1.2000
Overloading Binary Operators class Date { Date operator+(int days) const; }; Date Date::operator+(int days) const; { Date tmp=*this; // copy object for (int i=0; i < days; i++) ++tmp; return tmp; } Date d1(1,4,1999); Date d2=d1+25; // results in 26.4.2000
Overloading Binary Operators class Date { Date& operator+=(int days); // must be reference as += modifies // the left hand argument }; Date& Date::operator+=(int days) // return type reference to object { for (int i=0; i < days; i++) *this++; return *this; // return reference to object } Date d1(1,4,1999); d1+=25; // results in 26.4.2000
Overloading Relational Operators class Date { bool operator==(Date d) { return (day==d.day) && (month=d.month) && (year==d.year); }; bool operator<(Date d) { if (year < d.year) return true; else if (year==d.year) && (month < d.month) return true; else return (month==d.month) && (day < d.day); }; };
Overloading Binary Operators int Date::operator-(Date d) const { int days=0; if (*this > d) while (*this != ++d) days++; else while (*this != --d) days--; return days; } Date d1(24,4,1988); Date d2(13,3,1998); int diff = d1-d2; // diff = 42
Templates • A template is a place-holder for an arbitrary built-in or user-defined data type • Templates make is possible to use one function or class to handle many different data types • Function templates allow a parameter to assume an arbitrary data-type • Class templates allow a member data to assume an arbitrary data-type • Templates are another example for polymorphism
Function Templates int max(int a, int b) // one max function for int { if (a>b) return a; else return b; } double max(double a, double b) // max function for double { if (a>b) return a; else return b; }
Function Templates template <class Type> // class Type placeholder for concrete data type Type max( Type a, Type b) // substitute templateType for concrete type { if (a>b) return a; else return b; // identical code } void main() { int a=3, b=2; Date d1(17,5,1998); // assume operator > is defined for class Date Date d2(23,6,1997); int c=max(a,b); // template T replaced with int char z=max(’f’,’q’); // template T replaced with char Date d3=max(d1,d2); // template T replaced with date }
Function Templates one function template in source file template <class T> T max(T a, T b) { … }; argument type determines function instantiation Date d1,d2,d3; d3=max(d1,d2); char c1,c2,c3; c3=max(c1,c2); int i1,i2,i3; i3=max(i1,i2); int max(int a, int b) { … }; char max (char a, char b) { … }; Date max (Date a, Date b) { … };
Class Templates Array.h template <class Type> // template class Type class Array // array of arbitrary data type { public: Array(unsigned int sz); Type& operator[](unsigned int i); // returns a reference to i-th element Type operator()(unsigned int i); // returns the value of i-th element private: static int max_size=100; unsigned int size; Type array[100]; // placeholder for concrete data type };
Class Templates Array.C #include ”Array.h” template class<Type> Array<Type>::Array(unsigned int sz) { if (sz > max_size) size=max_size; else size=sz; } template class<Type> Type& Array<Type>::operator[](unsigned int i) { if (i<size) return array[i]; } template class<Type> Type Array<Type>::operator()(unsigned int i) { if (i<size) return array[i]; }
Class Templates Array<double> x(20); // instantiates a double array of size 20 Array<Date> dates(10); // instantiates a Date array of size 10 Date christmas(24,12,2001); x[10]=5.7; // operator [] returns reference can be used on rhs dates[3]=christmas; x[11]=x(10)+3.4; // operator () returns value can only be used on lhs x[0]=1.2; for (int i=1; i<20;i++) x[i]=x(i-1)*1.2; for (int i=0; i<10;i++) dates[i]++; // increment all dates by one calendar day
Class Templates • G++ has two compiler options • -fexternal-templates • -fno-external-templates • The later compiler directive is the default one and you need to arrange for all necessary instantiations to appear in the implementation file (.C) for example in Array.C #include Array.h template class<Type> Array<Type>::Array(unsigned int sz) { ... } ... template class Array<double>; // explictly instantiate Array<double> template class Array<Date>; // explictly instantiate Array<Date>
Pointers • Pointers • Pointers and Arrays • Pointers and function arguments • Dynamic memory management • New and delete
Pointers • Pointers are used to: • Access array elements • Passing arguments to functions when the function needs to modify the original argument • Passing arrays and strings to functions • Obtaining memory from the system • Creating data structures such as linked lists • Many operations that require pointers in C can be carried out without pointes in C++ using reference arguments instead of pointers, strings instead of char arrays or vectors instead of arrays • Some operations still require pointers, for example creating data structures such as linked lists and binary trees
Pointers • Each variable in a program occupies a part of the computer’s memory, for example an integer variable occupies 4 bytes of memory • The location of the piece of memory used to store a variable is called the address of that variable • An address is some kind of number similar to house numbers in a street that is used to locate the information stored in that particular variable int i; address of i 0x1054 10101011 0x1055 00001111 0x1056 10001000 0x1057 11100011 char c; address of c 0x1058 00111011 short s; address of s 0x1059 10111100 0x1060 11001100
Pointer Variables • A pointer variable is a variable that holds address values • Each data type has its own pointer variable, pointer to int, pointer to double, pointer to char, … • C/C++ uses the address-of operator & to get the address of an variable • C/C++ uses the indirection or contents-of operator * to access the value of the variable pointed by int i=17; int* ptr; // defines a pointer to an integer variable ptr= &i; // assign the address of x to pointer cout << *ptr << endl; // prints contents of variable i
Pointer Variables 0x1054 int i; int *ptr; address of 17 contents of ptr=&i; cout << *ptr << endl;
Pointer Variables int v; // defines variable v of type int int w; // defines variable w of type int int *p; // defines variable p of type pointer to int p=&v; // assigns address of v to pointer p v=3; // assigns value 3 to v *p=7; // assigns value 7 to v p=&w; // assigns address of w to pointer p *p=12; // assigns value 12 to w • Using the indirection operator *p to access the contents of a variable is called indirect addressing or dereferencing the pointer
Pointers and Arrays • There is a close association between pointers and arrays • Arrays can be accessed using pointers • The name of an array is also a constant pointer to the data type of the elements stored in the array int array[5] = { 23, 5, 12, 34, 17 }; // array of 5 ints for (int i=0; i< 5; i++) cout << array[i] << endl; // using index to access elements for (int i=0; i< 5; i++) cout << *(array+i) << endl; // using pointer to access elements // array is of type pointer to integer
Pointers as Function Arguments • C/C++ offers three different ways to pass arguments to a function • by value : void f(int x); • by reference : void f(int& x); • by pointer : void f(int* x); • In passing by value the function obtains only a local copy of the variable, so that changes to the local variable have no impact on the argument with which the function was invoked • In passing by reference and passing by pointer the function manipulates the original variable rather than only a copy of it
Pointers as Function Arguments void swap( double& x, double& y) { double tmp=x; x=y; // access variable by its alias name y=tmp; } void swap( double* ptr1, double* ptr2) { double tmp=*ptr1; *ptr1=*ptr2; // de-referencing pointer *ptr2=tmp; } double a=3.0; double b=5.0 swap(a,b); // call by reference to variables a and swap(&a, &b); // call by pointer using the addresses of a and b
BubbleSort void bsort (double *ptr, int n) // pass pointer to array and // size of array as arguments to bsort { int j,k; // indices to array for (j=0; j<n-1; j++) // outer loop for(k=j+1; k<n; k++) // inner loop starts at outer if(*(ptr+j) > *(ptr+k)) swap(ptr+j,ptr+k); } double array[6] = { 2.3, 4.5, 1.2, 6.8, 0.8, 4.9 }; bsort(array,n); // sort the array
Const Modifiers and Pointers • The use of the const modifier with pointers is confusing as it can mean two things • const int* cptrInt; // cptrInt is a pointer to a const int You can not the change the value of the integer that cptrInt points to but you can change the pointer itself • int* const ptrcInt; // ptrcInt is a constant pointer to int You can change the value of the integer that ptrcInt points to but you can not change the pointer itself
Memory Management • In order to create an array in C/C++ you have to know its size in advance during compile time, in other words it has to be a constant int size; cout << ”Enter size of array : ”; cin >> size; int array[size]; // ERROR size has to be a constant • Solution in C++, use vector class from the STL which is expandable
Memory Management Date* CreateDate() // allows the user to create a date object { int day, month, year; char dummy; cout << ”Enter dd/mm/yyyy :”; cin >> day >> dummy >> month >> dummy >> year; Date date(day, month, year); return &date; // ERROR!! Scope of date ends with end of function } Date *ptr; ptr=CreateDate(); // call CreateDate() to generate a new date cout << ”You entered ” << *ptr << endl; // variable to which ptr points no longer exist , segmentation fault !!!
Memory Management • The new operator in C++ can be used to create objects on the heap that are ”alive” after returning from a function • Objects allocated in dynamic memory are called heap objects or to be ”on free store” and have a permament existence Date* CreateDate() // allows the user to create a date object { int day, month, year; char dummy; cout << ”Enter dd/mm/yyyy :”; cin >> day >> dummy >> month >> dummy >> year; Date *tmpptr = new Date(day, month, year); return tmpptr; // returns pointer to heap object } Date *ptr; ptr=CreateDate(); // call CreateDate() to generate a new date cout << ”You entered ” << *ptr << endl; // ok, ptr refers to heap object
Memory Management • New can also be used to allocate blocks of memory • The delete operator is used to release the memory allocated with new once it is no longer needed #include <cstring> char *str =”This is an old C-style string”; int len=strlen(str); // computes the length of str char *ptr; // create a pointer to char ptr = new char[len+1]; // set aside memory string + ’\0’ strcpy(ptr,str); // copy str to new memory cout << ”ptr=” << ptr << endl; delete [] ptr; // release ptr’s memory
New Operator in Constructors class String // user-defined string class { private: char* str; // pointer to block of characters public: String(char* s) // one-argument constructor { int length=strlen(s); // length of string argument str = new char[length+1]; // allocate memory strcpy(str,s); // copy argument to it } ~String() // destructor { delete [] str; } void Display() { cout << str << endl; } }; String mystring=”This is my string of Type String”; mystring.Display();
Pointers to Objects • Pointers can point to objects as well as to built-in data types Date date; // define a named Date object date.Set(12,3,1996); // set the date date.Display(); // display the date Date *dateptr; // define a pointer to a Date object dateptr=new Date; // points to new Date object dateptr->Set(9,12,1999); // set date using -> operator dateptr->Display(); // display date (*dateptr).Display(); // works as well but less elegant
Linked List Example • A linked list is composed of a chain of elements (links). Each element contains some data and a pointer to the next element in the list. • In a double linked list, each element also contains a pointer to its predecessor. Element Element Element next data next data next data Element Element Element next prev data next prev data next prev data
Linked List Example struct link // one element of list { int data; // data item link *next; // pointer to next element }; class linklist { private: link* first; // pointer to first link public: linklist() { first = NULL;} // no argument constructor void push_back(int d); // add new element to the end of list int pop_back(); // delete last element and return data value void push_front(int d); // add new element to the front of list int pop(); // delete first element and return data value void display(); // display all elements in list }
Linked List Example void linklist::push(int d) // add data item at the front { link* newlink = new link; // create a new link newlink->data = d; // assign new data d newlink->next=first; // it points to the next link first = newlink; // now first points to this link }
Linked List Example int linklist::pop() // remove element at the front { int tmp_data = first->data; link* tmp=first; first=first->next; delete tmp; // free storage return tmp_data; } int linklist::pop_back() // remove element at the end { link* tmp=first; while (tmp->next != NULL) tmp=tmp->next; int tmp_data = tmp->data; delete tmp; // free storage return tmp_data; }
Linked List Example void linklist::push_back(int d) // add data item at the end { link* newlink = new link; // create a new link newlink->data = d; // assign new data d newlink->next = 0; // points to nil link* tmp=first; if (tmp == NULL) // empty list first=newlink; else { while (tmp->next!=NULL) tmp=tmp->next; tmp->next=newlink; // it points to the next link } }
Linked List Example void linklist::display() // display all links { link* tmp=first; // set ptr to first link while(tmp != NULL) // until ptr points beyond last link { cout << current->data << ” ”; // print data current=current->next; // move to next link } }
Linked List Example template <class T> struct link // one element of list { T data; // data item link *next; // pointer to next element }; template <class T> class linklist { private: link* first; // pointer to first link public: linklist() { first = NULL;} // no argument constructor void push(T t); // add data item (one link) T pop(); void display(); // display all links }
Linked List Example template <class T> void linklist<T>::push(T t) // add element at the front { link* newlink = new link; // create a new link newlink->data = t; // give it data d newlink->next=first; // it points to the next link first = newlink; // now first points to this link } template <class T> void linklist<T>::display() // display all links { link* current=first; // set ptr to first link while(current != NULL) // until ptr points beyond last link { cout << current->data << ” ”; // print data current=current->next; // move to next link } }