lecture 15
DESCRIPTION
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) - PowerPoint PPT PresentationTRANSCRIPT
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
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
base class A
Feature B
Feature A
subclass
Feature B
Feature A
Feature C
Feature D
base class B
Feature D
Feature C
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 compiledt.Date::add(4); // uses add of class Datedt.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
class B class C
class D
diamond shapedinheritance tree
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
template <class T>T max(T a, T b)
{ … };
int max(int a, int b){ … };
int i1,i2,i3;i3=max(i1,i2);
char max(char a, char b)
{ … };
char c1,c2,c3;c3=max(c1,c2);
Date max(Date a, Date b)
{ … };
Date d1,d2,d3;d3=max(d1,d2);
one function templatein source file
argument type determines function instantiation
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.htemplate 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
10101011000011111000100011100011
0x10540x10550x10560x1057
001110110x1058101111000x1059110011000x1060
int i; address of i
char c;address of cshort s; address of s
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
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.0swap(a,b); // call by reference to variables a andswap(&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 datecout << ”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 datecout << ”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.
nextdata
Element Element Element
nextdata
nextdata
Element Element Elementnextprevdata
nextprevdata
nextprevdata
Linked List Examplestruct 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 Exampleint 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 Exampletemplate <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 Exampletemplate <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 } }