Topics on Ad Hoc Polymorphism

110
1 Topics on Ad Hoc Polymorphism Class-Defined Conversions Overloading and Function Selection Friend Functions Unary Operator Overloading Binary Operator Overloading Overloading Assignment & Subscript Operators Overloading Operator () for Indexing Overloading new and delete More Signature-Matching Polynomial:Type And Language Expectations

description

Topics on Ad Hoc Polymorphism. Class-Defined Conversions Overloading and Function Selection Friend Functions Unary Operator Overloading Binary Operator Overloading Overloading Assignment & Subscript Operators Overloading Operator () for Indexing Overloading new and delete - PowerPoint PPT Presentation

Transcript of Topics on Ad Hoc Polymorphism

Page 1: Topics on Ad Hoc Polymorphism

1

Topics on Ad Hoc Polymorphism

Class-Defined Conversions Overloading and Function Selection Friend Functions Unary Operator Overloading Binary Operator Overloading Overloading Assignment & Subscript Operators Overloading Operator () for Indexing Overloading new and delete More Signature-Matching Polynomial:Type And Language Expectations

Page 2: Topics on Ad Hoc Polymorphism

2

General Polymorphism

Polymorphism is a means of giving different meanings to the same message

The meanings are dependent on the type of data being processed

Go getme a ball

Page 3: Topics on Ad Hoc Polymorphism

3

Type Conversions

Conversion is the explicit or implicit change of value between types

Conversions provide a form of polymorphism

Float Int

Page 4: Topics on Ad Hoc Polymorphism

4

Ad Hoc Polymorphism

Overloading functions gives the same function name different meanings: ad hoc polymorphism

Name has different interpretations that depend on function selection based on signature-matching algorithm for C++

print (the int) 3

print (the matrix) 2.2 3.3 5.1 9.3

71.3 6.0 9.9 12.55

print (the shape)

Page 5: Topics on Ad Hoc Polymorphism

5

Overloading and OOP

The LOOK and FEEL principle of OOP is that user-defined types must enjoy the same privileges as native types

Client expects convenience without regard to native/nonnative distinction

Supplier needs to achieve ease of use for ADTs

Native types in the kernel language can be mixed in expressions because it is convenient and would otherwise be burdensome to designate conventionally expected conversions

Page 6: Topics on Ad Hoc Polymorphism

6

New Cast Notation

A functional notation is equivalent to a casttype-name (expression)

The type must be expressible as an identifier

Page 7: Topics on Ad Hoc Polymorphism

7

Equivalent Expressions and Casting

x = float(i); //C++ functional notationx = (float) i; //equivalent to abovep = (int*) q; //legal castp = int*(q); //illegaltypedef int* int_ptr; //equivalentp = int_ptr(q);

Functional notation is the preferred style

Page 8: Topics on Ad Hoc Polymorphism

8

Class-defined Conversions

Explicit type conversion of an expression is necessary when either the implicit conversion is not desired or the expression is not legal otherwise

To achieve the integration of ADTs and native types there are two mechanisms for having a member function provide an explicit conversion

conversion constructors class-name::operator type ( )

complex::complex(double) complex::operator double()

double complex complex double

Page 9: Topics on Ad Hoc Polymorphism

9

Constructors and Type Conversion

A constructor of one argument is de facto a type conversion from the argument's type to the constructor's class type

string::string(const char* p) { len = strlen(p); s = new char[len + 1]; strcpy(s, p); }

This is automatically a type transfer from char* to string and it is available both explicitly and implicitly

Page 10: Topics on Ad Hoc Polymorphism

10

The Conversion Operator

General form for conversion member function operator type() { . . . }

A conversion function must be a non-static member function without a return type and with an empty argument list

These conversions occur implicitlyin assignment expressions

in arguments to functions

in values returned from functions

Page 11: Topics on Ad Hoc Polymorphism

11

Conversion Operator to Native char*

string::operator char*(){ char* q = new char[len + 1]; strcpy(q, s); return (q);}

This defines a special conversion function inside the string class to convert from a string to the native type char *

This form doesn't provide access to the underlying string

Page 12: Topics on Ad Hoc Polymorphism

12

Explicit & Implicit String Conversions

string s;char* logo = "Geometrics Inc";

//perform explicit conversion then assignments = string(logo);

//implicit invocation of conversions = logo;

These are conversions from an already defined type to a user-defined type

It is not possible for the user to add a constructor to a native type such as int or double

Page 13: Topics on Ad Hoc Polymorphism

13

A conversion member function of the form A::operator B() and a constructor of the form B::B(const A&) both provide conversions from type A objects to type B objects

Having both can result in ambiguity errors

A B

A B

Ambiguity and Conversions

Page 14: Topics on Ad Hoc Polymorphism

14

Overloading print()

print(int)

print(int, int)

print(foo_bar)

Page 15: Topics on Ad Hoc Polymorphism

15

Overloaded Functions in C++

Overloaded functions are an important in C++

The overloaded meaning is selected by matching the argument list of the function call to the argument list of the function declaration

When an overloaded function is invoked, the compiler must have a selection algorithm with which to pick the appropriate function

The algorithm that accomplishes this depends on what type conversions are available

Page 16: Topics on Ad Hoc Polymorphism

16

Function Overload Selection Algorithm

1. Use an exact match if found

2. Try standard type promotions

3. Try standard type conversions

4. Try user-defined conversions

5. Use a match to ellipsis if found

Page 17: Topics on Ad Hoc Polymorphism

17

Best Match and Ambiguities

A best match must be unique and it must be best on at least one argument and as good on all other arguments as any other match

Ambiguity of more than 1 possible match is illegal

Default arguments can lead to ambiguities

Page 18: Topics on Ad Hoc Polymorphism

18

Declarations int i; double w; complex z; char c, *p; void f(int);f(i); exact matchf(c); standard promotionf(w); standard conversionf(z); user-defined promotionf(p); illegal

Function Selection Algorithm In Use

Page 19: Topics on Ad Hoc Polymorphism

19

Function Overloading (1 of 5)

// Title: greater#include <iostream.h>#include <math.h> //for sqrtclass complex {public: complex(double r): real(r), imag(0.0) { } void assign(double r, double i) {real = r; imag = i; } void print() {cout<< real<< " + "<< imag << "i ";} operator double() {return (sqrt(real*real+imag*imag));}private: double real, imag;};

Page 20: Topics on Ad Hoc Polymorphism

20

Function Overloading (2 of 5)

inline int greater(int i, int j) { return ( i > j ? i : j); }

inline double greater(double x, double y) { return ( x > y ? x : y); }

inline complex greater(complex w,complex z) { return ( w > z ? w : z); }

Page 21: Topics on Ad Hoc Polymorphism

21

Function Overloading (3 of 5)

main(){ int i = 10, j = 5; float x = 7.0; double y = 14.5; complex w(0), z(0), zmax(0); w.assign(x, y); z.assign(i, j); cout << "compare " << i << " and " << j << " greater is " << greater(i, j) << endl; cout << "compare " << x << " and " << y << " greater is " << greater(x, y) << endl; cout << "compare " << y << " and " ;

Page 22: Topics on Ad Hoc Polymorphism

22

Function Overloading (4 of 5)

z.print(); cout << " greater is " << greater(y, double(z)) << endl; zmax = greater(w, z); cout << "compare "; w.print(); cout << " and "; z.print(); cout << " greater is "; zmax.print(); cout << endl;}

Page 23: Topics on Ad Hoc Polymorphism

23

Function Overloading (5 of 5)

The output from this program is

compare 10 and 5 greater is 10compare 7 and 14.5 greater is 14.5compare 14.5 and 10 + 5i greater is 14.5compare 7 + 14.5i and 10 + 5i greater is 7 + 14.5i

Page 24: Topics on Ad Hoc Polymorphism

24

Comments on the greater Program

Three distinct functions are overloaded

The most interesting has complex type for its argument list variables and its return type

The conversion member function operator double is required to evaluate w > z

The complex variables w and z are converted to double

Silently what happens is

double(w) > double(z) ? w : z;

Page 25: Topics on Ad Hoc Polymorphism

25

Friend Functions

The keyword friend is a function specifier which gives a nonmember function access to the hidden members of the class

Its use is a method of escaping the data-hiding restrictions of C++

There must be a good reason for escaping these restrictions as they are important to reliable programming

Page 26: Topics on Ad Hoc Polymorphism

26

Letting Non-members in

I’m a friend, so let me in without a membership card, please.

Show membershipcard to get in

OK, come in.

Page 27: Topics on Ad Hoc Polymorphism

27

Reasons for Using Friend Functions

Friend access follows certain understood situations that would othrwise be inconvenient

Operator overloading of binary operators

Some functions need access where the first argument is not properly a class or is a class argument whose source cannot be modified with additional members

Overriding efficiency concerns

Special relationship between classes

Page 28: Topics on Ad Hoc Polymorphism

28

Using Friend Functions

A friend function declaration must appear inside the class declaration to which it is a friend

The function is prefaced by the keyword friend and can appear in private or public part

A member function of one class can be a friend function of another class

The member function is declared in the friend's class using the scope resolution operator

If all member functions of one class are friend functions of a second class, then use friend class class-name

Page 29: Topics on Ad Hoc Polymorphism

29

Access via friends

class foo_bar { friend ostream& operator<< (ostream &, foobar &); . . . };

Because << is tied to ostream class it is not readily modifiable there

As a consequence we need operator << to be either a friend or an ordinary function

The relationship to I/O frequently needs appropriate and efficient access to state

Page 30: Topics on Ad Hoc Polymorphism

30

Assignment Compatible Conversion

class complex { . . . friend complex operator+(complex, complex); . . .};

1 + w; //with member function this failsw + 1; //this is OK either way

Symmetry of application of assignment compatible conversion rules for arguments is desirable

Page 31: Topics on Ad Hoc Polymorphism

31

Separating Components into Classes

class tree;class node { . . . friend class tree; . . .};

A special relationship holds between whole and part thatfavors separating thesecomponents

Page 32: Topics on Ad Hoc Polymorphism

32

Sub-component Access

friend vect mpy(const vect&, const matrix&);

Need efficient sub-component access to implement a basic operation

More generally, classes must interact intimately

Page 33: Topics on Ad Hoc Polymorphism

33

Using Friends

Multiply vector by matrix could be written efficiently if it had access to both classes

It would be a friend function of both classes

Safe access is provided with member functions vect::element() and matrix::element()

We could write a function using this access that would multiply without requiring friend status, but the price in functional call overhead and array bounds checking would make such a matrix multiply unnecessarily inefficient

Page 34: Topics on Ad Hoc Polymorphism

34

Using Friends (1 of 3)

// Title: matrix_v

class matrix; //forward referenceclass vect {public: friend vect mpy(const vect& v, const matrix& m); . . .private: int* p; int size;};

Page 35: Topics on Ad Hoc Polymorphism

35

Using Friends (2 of 3)

class matrix { //stores integer elementspublic: friend vect mpy(const vect& v, const matrix& m); . . .private: int** base; int row_size, column_size;};

Page 36: Topics on Ad Hoc Polymorphism

36

Using Friends (3 of 3)

vect mpy(const vect& v, const matrix& m){ if (v.size != m.row_size) { //incorrect sizes cerr << "multiply failed—sizes bad" << v.size << " & " << m.row_size; exit(1); } vect ans(m.column_size); //use privileged int i, j; //access to p for (i = 0; i <= m.ub2(); ++i) { ans.p[i] = 0; for (j = 0; j <= m.ub1(); ++j) ans.p[i] += v.p[j] * m.base[j][i]; } return (ans);}

Page 37: Topics on Ad Hoc Polymorphism

37

Controversy of Using Friend Functions

A neat, orderly design principle is that only member functions should have access to the hidden implementation of the ADT

The friend function straddles this boundary since it has access to private members but is not itself a member function

The friend function can be used to provide quick fixes to code that needs access to the implementation details of a class

The mechanism can be abused easily

Page 38: Topics on Ad Hoc Polymorphism

38

46

Notational Convenience & Operators

Just as a function name, such as print, can begiven a variety of meanings that depend on itsarguments, so can an operator, such as +, begiven additional meanings

Overloading operators allows ADTs to use C++expression syntax

It is an important notational convenience and inmany instances leads to shorter, more readableprograms

38

Page 39: Topics on Ad Hoc Polymorphism

39

Operator Overloading (1 of 2)

47

Operator Overloading (1 of 2)

Keyword operator used to overload C++operators

Associativity & precedence remain the same Operator overloading with other than member

functionsarguments are passed as parameters

Unary operator member function argumentsimplicitly passed class variableempty argument list

Binary operator member function argumentsimplicitly passed class variablelone argument list parameter

39

Page 40: Topics on Ad Hoc Polymorphism

4040

48

Operator Overloading (2 of 2)

Available operators can be overloaded:arithmetic logicalcomparison equalityassignment bitsubscript [] function call ()class pointer -> member pointer ->*new deleteautoincrement ++ autodecrement --

These operators cannot be overloaded:member . member object selector .*sizeof conditional expression ?:scope resolution ::

40

Page 41: Topics on Ad Hoc Polymorphism

4141

49

Using a Clock

Convert minutes to hours and seconds

41

Page 42: Topics on Ad Hoc Polymorphism

42

Unary Operator Overloading

Overload unary operators, such as !, ++, ~, and []

For this purpose we develop the class clock, which can be used to store time as days, hours, minutes, and seconds

Page 43: Topics on Ad Hoc Polymorphism

4343

50

Overloading clock (1 of 7)

class clock {private: unsigned long int tot_secs, secs, mins, hours, days;public: clock(unsigned long int i);//constructor and conversion void print(); //formatted printout void tick(); //add one second clock operator++() { tick(); return (*this); } clock operator—(const clock& c);

43

Page 44: Topics on Ad Hoc Polymorphism

44

51

Overloading clock (2 of 7)

friend clock operator*(unsigned long int m, const clock& c); friend clock operator*(const clock& c, unsigned long int m); friend clock operator+(const clock& c1, const clock& c2);};

44

Page 45: Topics on Ad Hoc Polymorphism

4545

52

Overloading clock (3 of 7)

void clock::print(){ cout <<days <<" d :" <<hours << " h :" <<mins <<" m :" <<secs << " s\n";}

inline clock::clock(unsigned long int i){ tot_secs = i; secs = tot_secs % 60; mins = (tot_secs / 60) % 60; hours = (tot_secs / 3600) % 24; days = tot_secs / 86400;}

45

Page 46: Topics on Ad Hoc Polymorphism

4646

53

Overloading clock (4 of 7)

void clock::tick(){ clock temp = clock(++tot_secs); secs = temp.secs; mins = temp.mins; hours = temp.hours; days = temp.days;}

void clock::reset(clock& c){ tot_secs = c.tot_secs; secs = c.secs; mins = c.mins; hours = c.hours; days = c.days;}

46

Page 47: Topics on Ad Hoc Polymorphism

47

47 54

Overloading clock (5 of 7)

clock operator*(unsigned long int m, const clock& c){ return (m * c.tot_secs);}

//allow * to work with clock*long or long*clock

clock operator*(const clock& c, unsigned long m){ return (m * c.tot_secs); //return m * c}

47

Page 48: Topics on Ad Hoc Polymorphism

48

48 55

Overloading clock (6 of 7)

//binary +clock operator+(const clock& c1, const clock& c2){ return (c1.tot_secs + c2.tot_secs);}

//binary -clock clock::operator—(const clock& c){ return( tot_secs — c.tot_secs);}

48

Page 49: Topics on Ad Hoc Polymorphism

49

56

Overloading clock (7 of 7)

main(){ clock t1(59), t2(172799); cout << "initial times are\n"; t1.print(); t2.print(); ++t1; ++t2; cout << "after one second times are\n"; t1.print(); t2.print(); t2 = t1 + t2 - t1 - t1; t1.print(); t2.print(); t1 = 3 * t2; t1.print(); t2.print();}

49

Page 50: Topics on Ad Hoc Polymorphism

50

Comments on the clock Program

The constructor performs the usual conversions from tot_secs to days, hours, minutes, and seconds and acts as a conversion function that properly updates the time

The member function tick constructs clock temp, which adds one second to the total time

Page 51: Topics on Ad Hoc Polymorphism

51

Unary Operator Overloading for Clock

clock operator++() { tick(); return (*this); }

This class overloads the prefix increment operator which updates the implicit clock variable and returns the updated value

The overloaded operator is a member function and can be invoked on its implicit single argument

Page 52: Topics on Ad Hoc Polymorphism

52

Member v. Non-Member Overloading

Overload prefix ++ using a friend function with call-by-reference:

clock operator++(clock& cl) { cl.tick(); return (cl); }

The decision to choose between a non-member and a member function typically depends on whether implicit conversion operations are available and desirable

Explicit argument passing, as in non-member functions, allows the argument to be automatically coerced

Page 53: Topics on Ad Hoc Polymorphism

53

Binary Operator Overloading

When a binary operator is overloaded using a member function, it has as its first argument the implicitly passed class variable and as its second argument the lone argument list parameter

A friend function or an ordinary function has both arguments specified in the parameter list

An ordinary function cannot access private members

Page 54: Topics on Ad Hoc Polymorphism

54

Binary Addition Friend Function

friend clock operator+(const clock& c1,const clock& c2)

Both arguments are candidates for assignment conversions

clock operator+(const clock& c1, const clock& c2) { return (c1.tot_secs + c2.tot_secs); }

Both arguments are specified explicitly

The constructor converts unsigned long int expression into a clock value

Page 55: Topics on Ad Hoc Polymorphism

55

Binary Subtraction Member Function

clock operator-(const clock& c);

In the - operation, there is an implicit first argument which takes some getting used to and which can cause asymmetric behavior for binary operators

clock clock::operator-(const clock& c){ return (tot_secs - c.tot_secs);}

Page 56: Topics on Ad Hoc Polymorphism

56

Binary Multiplication Friend Function

The multiplication operation is a binary operation with one argument an unsigned long int and the second argument a clock variable

clock operator*(unsigned long int m, const clock& c){ return(m * c.tot_secs);}

Implementation forces the multiplication to have a fixed ordering that is type-dependent

Common practice to write a second overloaded function to allow either ordering of operands

Page 57: Topics on Ad Hoc Polymorphism

57

Using the Binary clock Operations

int i = 5;clock c(900), d(800);c + i //legal: i converted to a clocki + c //legal: i converted to a clockc — i //legal: i converted to a clockc.operator—(i) //function call notationi — c //illegal: i is not a clocki.operator—(c) //illegal: function call notationi * c //legal

As seen clearly in the use of function call notation, the variable i is not a clock and does not "understand" the meaning of minus

Page 58: Topics on Ad Hoc Polymorphism

58

Lvalues and Rvalues

A = B

c[i] = 5 + D[j]

Page 59: Topics on Ad Hoc Polymorphism

59

Overloading Assignment & Subscript

C++ has reference declarations, and such type modifiers produce lvalues

lvalue stands for location value

On the right side of an assignment expression, an lvalue is automatically dereferenced

On the left side of an assignment expression, an lvalue specifies where a value is to be stored

Subscripting uses of these properties of lvalues

For ADTs define expressions such as subscript & assignment, unless defaults are satisfactory

Page 60: Topics on Ad Hoc Polymorphism

60

Re-implementing the Class vect

The reimplemented vect class has several improvements to make it safer and more useful

A constructor that converts an ordinary integer array to a safe array allows us to develop code using safe arrays and later convert the same code to run efficiently using ordinary arrays

The public data member ub is changed to a member function preventing a user from introducing a program error by modifying ub

The subscript operator [] is overloaded and replaces the member function element

Page 61: Topics on Ad Hoc Polymorphism

61

Making a Safe Array

5715

There isn’t a6th one to change!Let’s

change the6th vectorelement.

Page 62: Topics on Ad Hoc Polymorphism

62

Safe Array with Subscripting (1 of 6)

class vect {public: vect(); //create a size 10 array vect(int n); //create a size n array vect(const vect& v); //init by vect vect(const int a[], int n); //init by array ~vect() { delete [] p}; int ub() const { return (size — 1); }//upper bound int& operator[](int i); //range checked element vect& operator=(const vect& v); //overload assign vect operator+(const vect& v); //overload addprivate: int* p; //base pointer int size; //number of elements};

Page 63: Topics on Ad Hoc Polymorphism

63

Safe Array with Subscripting (2 of 6)

//Add two further constructors//Constructor 1 converts a normal array

vect::vect(const int a[], int n){ asert (n > 0); size = n; p = new int[size]; assert (p); //throw xalloc; for (int i = 0; i < size; ++i) p[i] = a[i];}

Page 64: Topics on Ad Hoc Polymorphism

64

Safe Array with Subscripting (3 of 6)

//Constructor 2 is copy constructor

vect::vect(const vect& v){ size = v.size; p = new int[size]; assert (p); for (int i = 0; i < size; ++i) p[i] = v.p[i];}

Page 65: Topics on Ad Hoc Polymorphism

65

Safe Array with Subscripting (4 of 6)

The overloaded subscript operator takes an integer argument and tests value is within range

If so, it uses it to return the lvalue of the indexed element

int& vect::operator[](int i){ if (i < 0 || i > (size — 1)) { cerr << "illegal vect index: " << i << endl; exit(1); //throw boundserr(); } //later will use exceptions return (p[i]);}

Page 66: Topics on Ad Hoc Polymorphism

66

Safe Array with Subscripting (5 of 6)

vect& vect::operator=(const vect& v){ int s = (size < v.size) ? size : v.size; if (v.size != size) cerr << "copying different size " << "arrays " << size << " and " << v.size << endl; for (int i = 0; i < s; ++i) p[i] = v.p[i]; return (*this);}

Page 67: Topics on Ad Hoc Polymorphism

67

Safe Array with Subscripting (6 of 6)

vect vect::operator+(const vect& v){ int s = (size < v.size) ? size : v.size; vect sum(s); //vect * sumptr = new vect(s); if (v.size != size) cerr << "adding different size " << "arrays " << size << " and " << v.size << endl; for (int i = 0; i < s; ++i) sum.p[i] = p[i] + v.p[i]; return (sum); //return (*sumptr);}

Page 68: Topics on Ad Hoc Polymorphism

68

Comments on Subscript Function

An overloaded subscript operator has a return type and a single argument

It must be a non-static member function

It is good style to maintain the consistency between a user-defined meaning of the subscripting operator [] and standard usage

A most common function prototype is class name& operator[](integral type);

A reference value is returned in such functions that can be used on either side of an assignment expression

Page 69: Topics on Ad Hoc Polymorphism

69

Shallow Copy Semantics and vect

Provide your own assignment operator anytime pointers are part of the ADT implementation

When assignment is not overloaded its default is memberwise assignment of value

This is shallow copy semantics and can be incorrect

Class provider makes sure that default semantics are correct

If not, as is the case here with vect, the class provider must overload the construct with the correct semantics, or alternatively overload the assignment operator with error-signalling behavior

Page 70: Topics on Ad Hoc Polymorphism

70

Comments on Assignment Function

The explicit argument v.p[] is the right side of the assignment

The implicit argument, as represented by p[], is the left side of the assignment

The self-referential pointer is dereferenced and passed back as the value of the expression

Allows multiple assignment with right-to-left associativity

Function could have been written to return void, but then it would not allow multiple assignment

Page 71: Topics on Ad Hoc Polymorphism

71

Using vect Addition and Assignment

Meaningful with the extended class vect:

a = b; //a, b are type vecta = b = c; //a, b, c are type vecta = vect(data, DSIZE); //convert array data[DSIZE]a = b + a; //assignment and additiona = b + (c = a) + d; //complicated expression

The class vect is a full-fledged ADT

It behaves and appears in client code much as any built-in type behaves and appears

Page 72: Topics on Ad Hoc Polymorphism

72

Overloading Operator () For Indexing

Dynamically allocated two-dimensional arrays can be designed with the function call operator overloaded to provide element selection

The matrix is allocated as a column of pointers that are base addresses for a row of elements

assert.h provides a macro that dynamically tests a condition and reports on failure

The function call operator () is overloadable as a non-static member function

Provides an iterator operation or an operation requiring multiple indices

Page 73: Topics on Ad Hoc Polymorphism

73

Overloading () (1 of 5)

// Title: matrix#include <assert.h>

class matrix {public: matrix(int c, int r); ~matrix(); double& operator()(int i, int j) const { return (p[i][j]); } matrix& operator=(const matrix& m); matrix& operator+=(const matrix& m);private: int c_size, r_size; double **p;};

Page 74: Topics on Ad Hoc Polymorphism

74

Overloading () (2 of 5)

matrix:: matrix(int c, int r):c_size(c), r_size(r){ assert (c > 0 && r > 0); p = new double*[c]; assert (p); for (int i = 0; i < c; ++i) { p[i] = new double[r]; assert (p); }}

Page 75: Topics on Ad Hoc Polymorphism

75

Overloading () (3 of 5)

matrix:: ~matrix(){ for (int i = 0; i < c_size; ++i) delete [] p[i]; delete [] p;}

Page 76: Topics on Ad Hoc Polymorphism

76

Overloading () (4 of 5)

matrix& matrix::operator=(const matrix& m){ assert(m.c_size == c_size && m.r_size == r_size);

int i, j;

for (i = 0; i < c_size; ++i) for (j = 0; j < r_size; ++j) p[i][j] = m.p[i][j];

return (*this);}

Page 77: Topics on Ad Hoc Polymorphism

77

Overloading () (5 of 5)

matrix& matrix::operator+= (const matrix& m){ assert(m.c_size == c_size && m.r_size == r_size);

int i, j;

for (i = 0; i < c_size; ++i) for (j = 0; j < r_size; ++j) p[i][j] += m.p[i][j];

return (*this);}

Page 78: Topics on Ad Hoc Polymorphism

78

Comments on the matrix Program (1 of 2)

The constructor first allocates an array of pointer-to-double off the heap, then each array of double is allocated with its base address stored in a corresponding element p[i]

This scheme is necessary to provide correct addressing to individual matrix components regardless of size

The overloaded member function () gives a convenient multiple argument notation for element access which results in client code using expressions of the form m(i,j) to access explicit matrix elements

Page 79: Topics on Ad Hoc Polymorphism

79

Comments on the matrix Program (2 of 2)

Through an assertion or conditional statement, matrix indices are bounds-tested

Assertion macro is used with a precondition for arguments needed by the member function

The assertion code replaces an if-else statement that would perform an error exit

The matrix being assigned to must be the same size as the matrix expression being computed

Dereferencing the this pointer causes the lvalue of the matrix object to be returned

Page 80: Topics on Ad Hoc Polymorphism

80

Overloading new and delete

Many classes involve free store memory allocation and deallocation

The user of a class wants it to be as flexible and general as possible which can require more sophisticated use of memory than is provided by simple calls to operator new and delete

Operators new and delete can be overloadedProvides a simple mechanism for user-defined

manipulation of free store

Page 81: Topics on Ad Hoc Polymorphism

81

Memory Management Overloading

new gets memory

delete gets rid of memory

Both can be overloaded

Page 82: Topics on Ad Hoc Polymorphism

82

Overloading new and delete

// Title: alloc//malloc() and free() defined

#include <stdlib.h>

class X { . . .public: void* operator new(size_t size) { return (malloc(size)); } void operator delete(void* ptr) { free(ptr); } X(unsigned size) { new(size); } ~X() { delete(this); } . . .};

Page 83: Topics on Ad Hoc Polymorphism

83

Comments on the alloc Program

Overloaded forms of new() and delete() When a class overloads operator new(), the

global operator is still accessible using the scope resolution operator ::

One reason to overload these operators is to give them additional semantics

Provides diagnostic information or fault tolerance

The class can have a more efficient memory allocation scheme than provided by the system

Allocate specific memory pool

Defer deallocation and deallocate for a list of objects

Page 84: Topics on Ad Hoc Polymorphism

84

Placement Syntax and new

Placement syntax provides a comma-separated argument list used to select an overloaded operator new() with a matching signature

Additional arguments are often used to place the constructed object at a particular address

This form of new uses the new.h header file

Placement syntax allows the user to have an arbitrary signature for overloaded new operator

This signature is distinct from initializer arguments used by calls to new that select an appropriate constructor

Page 85: Topics on Ad Hoc Polymorphism

85

Placement Syntax and new overloaded

#include <iostream.h>#include <new.h>

char* buf1 = new char[1000]; //free storechar* buf2 = new char[1000];class object { . . .};

main(){ object *p = new(buf1) object; //allocate at buf1 object *q = new(buf2) object; //allocate at buf2 . . .}

Page 86: Topics on Ad Hoc Polymorphism

86

The delete Operator

The delete operator comes in two flavors void operator delete(void* p); void operator delete(void* p, size_t);

The first signature makes no provision for the number of bytes to be returned by delete

Programmer provides code that supplies this value

The second signature includes a size_t argument passed to delete which is provided by the compiler as size of object pointed at by p

Only one form of delete can be provided as a static member function in each class

Page 87: Topics on Ad Hoc Polymorphism

87

Using the new.h File

The new.h file has the function pointer _new_handler that calls the error handler for operator new

If memory is exhausted, the function pointer _new_handler is calls a default system routine

The user can specify an explicit out of free store routine, which can replace the default by using set_new_handler()

It is likely in future systems that new will throw an exception when free store is exhausted

Page 88: Topics on Ad Hoc Polymorphism

88

Simple Fault Tolerance: _new_handler

#include <new.h>

void heap_exhausted() //user-defined error handling{ cerr << "HEAP EXHAUSTED" << endl; exit(1);}

main(){ set_new_handler(&heap_exhausted); . . .//memory exhaustion is treated//heap_exhausted()};

Page 89: Topics on Ad Hoc Polymorphism

89

Comments on Simple Fault Tolerance

These class new() and delete() member functions are always implicitly static

new() is invoked before the object exists and therefore cannot have a this yet

delete() is called by the destructor, so the object is already destroyed

Page 90: Topics on Ad Hoc Polymorphism

90

More Signature Matching

The function argument type list is called its signature and order of the arguments is crucial

int sqr(int i); //int illegaldouble sqr(int i); //int illegalvoid print(int i = 0); //intvoid print(int i, double x); //int, doublevoid print(double y, int i); //double, int

When the print function is invoked, the compiler matches the actual arguments to the different signatures and picks the best match

Page 91: Topics on Ad Hoc Polymorphism

91

In general there are three possibilities:

a best match

an ambiguous match

no match

Without a best match, the compiler issues an appropriate syntax error

Match Possibilities

Page 92: Topics on Ad Hoc Polymorphism

92

2-Step Matching Algorithm

The matching algorithm has two parts

The first part determines a best match for each argument

For a given argument a best match is always an exact match

An exact match also includes trivial conversions

The second part sees if there is one function that is a unique best match in each argument

Page 93: Topics on Ad Hoc Polymorphism

93

Match Types

void print(int i = 0);void print(int i, double x);void print(double y, int i);

print(15); matches intprint('A'); converts and matches intprint(9.90); converts and matches intprint(str[]); no match wrong typeprint(15, 9); ambiguousprint(15.0, 9); matches double, intprint(15, 9.0); matches int, doubleprint(15.0, 9.0); ambiguousprint(i, j, k); no match too many argumentsprint(); match int by default

Page 94: Topics on Ad Hoc Polymorphism

94

Match Examples

Equally Good Not as Good T T& T* const T* T& T T* volatile T* T const T T& const T& T volatile T T& volatile T& T[] T* T(args) (*T)(args)

The six left-hand trivial conversions cannot be used to disambiguate exact matches

Page 95: Topics on Ad Hoc Polymorphism

95

Promotions and Matching

The matching rule distinguishes promotions from other standard conversions

Promotion goes from narrow type to wider typeGoing from char to int is a promotion

Promotions are better than other standard conversions

Among promotions, conversion from float to double and conversion from char, short, or enum to int are better than other promotions

Standard conversions include pointer conversions, explained for inheritance

Page 96: Topics on Ad Hoc Polymorphism

96

User-Defined Conversions and Matching

User-defined conversions include constructors of a single argument

This constructor can be implicitly called to perform a conversion from the argument type to its class type

This can happen for assignment conversions, as in the argument-matching algorithm

Page 97: Topics on Ad Hoc Polymorphism

97

Conversions & Matching clock (1 of 2)

//clock with a reset function

class clock {private: unsigned long int tot_secs, secs, mins, hours,days;public: //constructor & conversion clock(unsigned long int i); void print(); //formatted printout void tick(); //add one second clock operator++() {this —> tick(); return(*this);} void reset(const clock& c); //alternate to operator=()};

Page 98: Topics on Ad Hoc Polymorphism

98

Conversions & Matching clock (2 of 2)

void clock::reset(const clock& c){ *this = c;}

main(){ clock c1(900), c2(400); . . . c1.reset(c2); c2.reset(100); . . .}

Page 99: Topics on Ad Hoc Polymorphism

99

Comments on the clock Match

The call to reset(100) involves an argument match between int and clock that is a user-defined conversion invoking the constructor clock(unsigned)

Explicitly casting arguments can be both an aid to documentation and a useful way to avoid poorly understood conversion sequences

Page 100: Topics on Ad Hoc Polymorphism

100

Design of a Polynomial Class

What is the public behavior of the ADT?What implementation(s) should be used?

Limits?Efficiency?

What should its relationship be to other types?Explicit conversions?

Implicit conversions?

What is expected use of operator overloading?

Inheritance and friendship relationshipsWhere are special privileges required?

Extensibility concerns?

Page 101: Topics on Ad Hoc Polymorphism

101

Polynomial & Overload Operators (1 of 4)

class poly {public: poly(); poly(const poly& p); poly(int size, double coef[], int expon[]); ~poly() { release(); } void print() const;

//evaluate P(x) double operator()(double x) const;

Page 102: Topics on Ad Hoc Polymorphism

102

Polynomial & Overload Operators (2 of 4)

//Overloaded Operators poly& operator=(const poly& a); friend poly& operator+ (const poly& a, const poly& b); friend poly& operator— (const poly& a, const poly& b); friend poly& operator* (const poly& a, const poly& b); friend poly& operator/ (const poly& a, const poly& b); friend poly& operator—(const poly& a);//unary friend poly& operator+= (const poly& a, const poly& b);

Page 103: Topics on Ad Hoc Polymorphism

103

Polynomial & Overload Operators (3 of 4)

friend boolean operator== (const poly& a, const poly& b); friend boolean operator!= (const poly& a, const poly& b);private: term* h; int degree; void prepend(term* t); void add_term(term*& a, term*& b); void release(); void rest_of(term* rest); void reverse();

};

Page 104: Topics on Ad Hoc Polymorphism

104

Polynomial & Overload Operators (4 of 4)

poly& poly::operator=(const poly& a){ if (h != a.h) { //avoid a = a case release(); //garbage collect old value poly* temp = new poly(a); h = temp —> h; degree = temp —> degree; } return (*this);}

Page 105: Topics on Ad Hoc Polymorphism

105

Comments on the poly Class

We expect both the basic mathematical operations to work and the basic relationships among C++ operators to hold

It would be very undesirable to have operator=(), operator+(), and operator+=() all defined and not have a = a + b give the same result as a += b

Page 106: Topics on Ad Hoc Polymorphism

106

Summary of Ad Hoc Polymorphism (1 of 4)

A functional notation type-name (expression) is equivalent to a cast

A constructor of one argument is de facto a type conversion from the argument's type to the constructor's class type

A conversion from a user-specified type to a built-in type can be made by defining a special conversion function

Conversions occur implicitly in assignment, arguments to functions, and values returned from functions

Page 107: Topics on Ad Hoc Polymorphism

107

Summary of Ad Hoc Polymorphism (2 of 4)

The overloaded meaning is selected by matching the argument list of the function call to the argument list of the function declaration

The algorithm that accomplishes this depends on what type conversions are available

1. Use an exact match if found

2. Try standard type promotions

3. Try standard type conversions

4. Try user-defined conversions

5. Use a match to ellipsis if found

Page 108: Topics on Ad Hoc Polymorphism

108

Summary of Ad Hoc Polymorphism (3 of 4)

Keyword friend is a function specifier and it allows a nonmember function access to hidden members of the class of which it is a friend

A friend function or an ordinary function has both arguments specified in the parameter list

Overloading operators gives them new meanings for ADTs: the ADT can then be used in much the same way as a built-in type

Operator overloading uses either member functions or friend functions because they have privileged access

Page 109: Topics on Ad Hoc Polymorphism

109

Summary of Ad Hoc Polymorphism (4 of 4)

When a unary operator is overloaded using a member function, it has an empty argument list: single operator argument is implicit

When a binary operator is overloaded using a member function, its 1st argument is the implicitly passed class variable and its 2nd is the lone argument list parameter

Overloaded subscript, assignment, function call, and member access must be non-static member functions

new and delete can be overloaded for user-defined manipulation of free store

Page 110: Topics on Ad Hoc Polymorphism

110

110

2

C++ I/O Streams

C++ introduces iostream.h, the standard C++ library containing the input/output functions

The stream I/O is described as a set of classes in iostream.h

iostream.h overloads the put-to (insert) andget-from (extract) operators << and >>

Streams can be associated with files

110