You are on page 1of 77

1

Operator Overloading

8.1 Introduction
Thao tc trn cc i tng ca lp c thc hin bi gi cc thng ip ti cc i tng. K php gi hm ny cng knh, c bit l cc lp ton hc. Nn s dng tp cc ton t c sn ca C++ ch r cc thao tc ca i tng => gi l a nng ha ton t (operator overloading). Ton t << c s dng nhiu mc ch trong C++ l ton t chn dng (stream-insertion) v ton t dch chuyn tri. Tng t >> cng c a nng ha. : ton t trch dng (stream-extraction) v ton t dch chuyn phi. C++ cho php a nng ha hu ht cc ton t . Trnh bin dch pht sinh on m thch hp da trn kiu m trong ton t c s dng. Mt vi ton t c a nng ha thng xuyn, c bit l ton t gn v cc ton t s hc nh + v -.

8.2 CC NGUYN TC C BN CA A NNG HA TON T

C th s dng cc kiu c sn v c th nh ngha cc kiu mi. Cc kiu c th c s dng vi tp cc ton t phong ph. C th s dng cc ton t vi cc kiu do ngi dng nh ngha. C++ khng cho php to cc ton t mi, nhng cho php a nng ha cc ton t tn ti khi s dng vi cc i tng ca lp, chng c ngha thch hp vi cc kiu mi =>im mnh ca C++. Cc ton t c a nng ha bng cch vit mt nh ngha hm nh khi chng ta vit mt hm bnh thng, ngoi tr tn hm l t kha operator theo sau bi k hiu ca ton t c a nng ha. Prototype ca n c dng nh sau: type operator operator_symbol ( parameter_list ); s dng mt ton t cho cc i tng ca lp, ton t phi c a nng ha ngoi tr hai iu. Ton t gn c th s dng vi mi lp m khng cn a nng ha. Ton t a ch (&) cng c th c s dng vi cc i tng ca bt k lp no m khng cn a nng ha;

8.3 CC GII HN CA A NNG HA TON T

Phn ln cc ton t ca C++ c th c a nng ha.


+ ~ /= <<= -! %= == ->* * = ^= != , / < &= <= -> % > |= >= [] ^ += << && () & -= >> || new | *= >>= ++ delete

Cc ton t khng th a nng ha


. .* :: ?: sizeof

Ton t ngoc trn () l ton t gi hm. Sau tn hm c th cha nhiu tham s => ton t nhiu ngi. Th t u tin ca mt ton t khng th c thay i bi a nng ha. Tnh kt hp ca mt ton t khng th c thay i bi a nng ha. Khng th thay i s cc ton hng m mt ton t yu cu: a nng ha cc ton t mt ngi vn l cc ton t mt ngi .. Ton t ba ngi duy nht (?:) ca C++ khng th a nng ha. Cc ton t &, *, + v mi ton t c cc phin bn mt v hai ngi.; Cc phin bn mt v hai ngi ny c th c a nng ha ring bit. Vic a nng ha ton t ch lm vic vi cc i tng ca cc kiu do ngi dng nh ngha hoc vi mt s pha trn ca mt i tng ca kiu do ngi dng nh ngha v mt i tng ca mt kiu c sn. a nng ha mt ton t gn v mt ton t cng cho php cc lnh nh l: object2 = object2 + object1 khng bao hm ton t += cng c a nng ha php cc lnh nh l: object2 += object1 _=>Cn a nng ha r rng ton t += cho lp .

8.4 HM TON T L CC THNH VIN CA LP HOC KHNG L CC THNH VIN


Hm ton t c th l hm thnh vin hoc khng thnh vin; hm khng thnh vin thng l friend. Cc hm thnh vin s dng ngm con tr this cha mt trong cc tham s i tng lp ca chng. Tham s lp phi c lit k mt cch tng minh trong li gi hm khng thnh vin. Khi a nng ha (), [], -> hoc =, hm a nng ha ton t phi c khai bo nh mt thnh vin lp. i vi cc ton t khc, cc hm a nng ha ton t c th l cc hm khng thnh vin (thng l Friend). D ton t c ci t nh th no, ton t vn c s dng cng cch trong biu thc. Vy cch ci t no tt nht? Khi c ci t nh mt hm thnh vin, ton hng cc tri phi l mt i tng lp ca ton t. Nu ton hng bn tri phi l mt i tng ca lp khc hoc mt kiu c sn th hm ton t ny phi c ci t nh hm khng thnh vin. Mt hm ton t ci t nh hm khng thnh vin cn l mt friend nu hm phi truy cp n cc thnh vin private hoc protected. Cc hm thnh vin ch c gi khi ton hng tri ca mt ton t hai ngi l mt i tng c th ca lp , hoc khi ton hng n ca mt ton t mt ngi l mt i tng ca lp .

V d :xy dng lp s phc vi tn lp l Complex v a nng ha ton t +


#include <iostream.h> class Complex { private: double R, I; public: Complex(double R=0.0,double I=0.0);// Constructor mc nh void Print(); // Hin th s phc Complex operator+(Complex Z); // Php cng gia hai s phc Complex operator+(double R); // Php cng mt s phc vi mt s thc }; Complex::Complex(double T,double A) { R = T; I = A; } void Complex::Print() { cout<<'('<<R<<','<<I<<')'; } Complex Complex::operator + (Complex Z) { Complex Tmp; Tmp.R = R + Z.R; Tmp.I = I + Z.I; return Tmp; }

Complex Complex::operator + (double T) { Complex Tmp; Tmp.R = R + T; Tmp.I = I; return Tmp; } int main() { Complex X,Y(4.3,8.2),Z(3.3,1.1); cout<<"X: "; X.Print(); cout<<endl<<"Y: "; Y.Print(); cout<<endl<<"Z: "; Z.Print(); X = Y + Z; cout<<endl<<endl<<"X = Y + Z:"<<endl; X.Print(); cout<<" = "; Y.Print(); cout<<" + "; Z.Print(); X = Y + 3.5; cout<<endl<<endl<<"X = Y + 3.5:"<<endl; X.Print(); cout<<" = "; Y.Print(); cout<<" + 3.5"; return 0; }

Do a nng ha ton t + trn lp Complex v d trn, chng ta c th vit: X = Y + Z; Cu lnh ny c trnh bin dch hiu: X = Y.operator + (Z); Nh vy, trong biu thc Y + Z i tng bn tri ton t + (l i tng Y) l i tng m qua , hm thnh vin ton t operator + () c gi. Do hm thnh vin ton t + ch nhn mt tham s l i tng bn phi ton t v i tng bn tri ton t l i tng to li gi cho hm ton t v c truyn bi con tr this. Hm operator + () tr v mt i tng Complex. Do vy chng ta c th vit: (Y + Z).Print(); in trn mn hnh s phc ca i tng c tr v. i tng do Y + Z sinh ra nh vy l mt i tng tm thi. N s khng tn ti khi hm thnh Print() kt thc. Ton t + cho php mt chui php cng. Nn chng ta cng c th vit: X = X + Y + Z; Tuy nhin chng ta khng th no vit c cu lnh sau: X = 3.5 + Y; // Li !!! Lam the nao ?

10

cch a nng ha ton t


Biu thc a#b #a a=b Hm thnh vin a.operator#(b) a.operator#() a.operator=(b) Hm khng thnh vin operator#(a,b) operator#(a)

a[b] a(b) a-> a++ a--

a.operator[](b) a.operator()(b) a.operator->() a.operator++(0) a.operator--(0)

operator++(a,0) operator--(a,0)

11

8.5 A NNG HO CC TON T HAI NGI


Ton t V d Ton t V d Ton t V d

+ * / % ^ & | = < >

a+b a-b a*b a/b a%b a^b a&b a|b a=b a<b a>b

+= -= *= /= %= ^= &= |= << >> >>=

a+=b a-=b a*=b a/=b a%=b a^=b a&=b a|=b a<<b a>>b a>>=b

<<= == != <= >= && || , [] ->*

a<<=b a==b a!=b a<=b a>=b a&&b a||b a,b a[b] a->*b

V d : xy dng lp Complex v a nng ha cc ton t + - += -= v == != > >= < <= vi cc hm ton t l cc hm thnh vin #include <iostream.h> #include <math.h> class Complex { private: double R, I; public: Complex(); // Constructor mc nh Complex(double R,double I); Complex (const Complex & Z); // Constructor sao chp Complex (double R); // Constructor chuyn i void Print(); // Hin th s phc // Cc ton t ton hc Complex operator + (Complex Z); Complex operator - (Complex Z); Complex operator += (Complex Z); Complex operator -= (Complex Z);

12

13

// Cc ton t so snh int operator == (Complex Z); int operator != (Complex Z); int operator > (Complex Z); int operator >= (Complex Z); int operator < (Complex Z); int operator <= (Complex Z); private: double Abs(); // Gi tr tuyt i ca s phc };

14

Complex::Complex() { R = 0.0; I = 0.0; } Complex::Complex(double T,double A) { R = T; I = A;} Complex::Complex(const Complex & Z) { R = Z.R; I = Z.I; } Complex::Complex(double T) { R = T; I = 0.0; } void Complex::Print() { cout<<'('<<R<<','<<I<<')'; }

15

Complex Complex::operator + (Complex Z) { Complex Tmp; Tmp.R = R + Z.R; Tmp.I = I + Z.I; return Tmp; } Complex Complex::operator - (Complex Z) { Complex Tmp; Tmp.R = R - Z.R; Tmp.I = I - Z.I; return Tmp; } Complex Complex::operator += (Complex Z) { R += Z.R; I += Z.I; return *this; } Complex Complex::operator -= (Complex Z) { R -= Z.R; I -= Z.I; return *this; }

16

int Complex::operator == (Complex Z) { return (R == Z.R) && (I == Z.I); } int Complex::operator != (Complex Z) { return (R != Z.R) || (I != Z.I); } int Complex::operator > (Complex Z) { return Abs() > Z.Abs(); } int Complex::operator >= (Complex Z) { return Abs() >= Z.Abs(); } int Complex::operator < (Complex Z) { return Abs() < Z.Abs(); } int Complex::operator <= (Complex Z) { return Abs() <= Z.Abs(); } double Complex::Abs() { return sqrt(R*R+I*I); }

17

int main() { Complex X, Y(4.3,8.2), Z(3.3,1.1), T; cout<<"X: "; X.Print(); cout<<endl<<"Y: "; Y.Print(); cout<<endl<<"Z: "; Z.Print(); cout<<endl<<"T: "; T.Print(); T=5.3;// Gi constructor chuyn kiu cout<<endl<<endl<<"T = 5.3"<<endl; cout<<"T: "; T.Print(); X = Y + Z; cout<<endl<<endl<<"X = Y + Z: "; X.Print(); cout<<" = "; Y.Print(); cout<<" + "; Z.Print(); X = Y Z; cout<<endl<<"X = Y - Z: "; X.Print(); cout<<" = "; Y.Print(); cout<<" - "; Z.Print();

cout<<endl<<endl<<"Y += T i.e "; Y.Print(); cout<<" += "; T.Print(); Y += T; cout<<endl<<"Y: "; Y.Print(); cout<<endl<<"Z -= T i.e "; Z.Print(); cout<<" -= "; T.Print(); Z -= T; cout<<endl<<"Z: "; Z.Print(); Complex U(X);// Gi constructor sao chp cout<<endl<<endl<<"U: "; U.Print(); cout<<endl<<endl<<"Evaluating: X==U"<<endl; if (X==U) cout<<"They are equal"<<endl; cout<<"Evaluating: Y!=Z"<<endl; if (Y!=Z) cout<<"They are not equal => "; if (Y>Z) cout<<"Y>Z"; else cout<<"Y<Z"; return 0; }

18

19

Dng cc hm ton t +, - v cc hm ton t so snh l hm khng thnh vin.


class Complex { private: double Real,Imaginary; public: Complex(); // Constructor mc nh Complex(double R,double I); Complex (const Complex & Z); // Constructor sao chp Complex (double R); // Constructor chuyn i void Print(); // Hin th s phc friend Complex operator + (Complex Z1,Complex Z2); friend Complex operator - (Complex Z1,Complex Z2); Complex operator += (Complex Z); Complex operator -= (Complex Z); friend int operator == (Complex Z1,Complex Z2); friend int operator != (Complex Z1,Complex Z2); friend int operator > (Complex Z1,Complex Z2); friend int operator >= (Complex Z1,Complex Z2); friend int operator < (Complex Z1,Complex Z2); friend int operator <= (Complex Z1,Complex Z2); private: double Abs(); // Gi tr tuyt i ca s phc };

20

21

Complex::Complex() { Real = 0.0; Imaginary = 0.0; } Complex::Complex(double R,double I) { Real = R; Imaginary = I; } Complex::Complex(const Complex & Z) { Real = Z.Real; Imaginary = Z.Imaginary; } Complex::Complex(double R) { Real = R; Imaginary = 0.0; } void Complex::Print() { cout<<'('<<Real<<','<<Imaginary<<')'; } Complex operator + (Complex Z1,Complex Z2) { Complex Tmp; Tmp.Real = Z1.Real + Z2.Real; Tmp.Imaginary = Z1.Imaginary + Z2.Imaginary; return Tmp; }

22

Complex operator - (Complex Z1,Complex Z2) { Complex Tmp; Tmp.Real = Z1.Real - Z2.Real; Tmp.Imaginary = Z1.Imaginary - Z2.Imaginary; return Tmp; } Complex Complex::operator += (Complex Z) { Real += Z.Real; Imaginary += Z.Imaginary; return *this; } Complex Complex::operator -= (Complex Z) { Real -= Z.Real; Imaginary -= Z.Imaginary; return *this; }

23

int operator == (Complex Z1,Complex Z2) { return (Z1.Real == Z2.Real) && (Z1.Imaginary == Z2.Imaginary); } int operator != (Complex Z1,Complex Z2) { return (Z1.Real != Z2.Real) || (Z1.Imaginary != Z2.Imaginary); } int operator > (Complex Z1,Complex Z2) { return Z1.Abs() > Z2.Abs(); } int operator >= (Complex Z1,Complex Z2) { return Z1.Abs() >= Z2.Abs(); } int operator < (Complex Z1,Complex Z2) { return Z1.Abs() < Z2.Abs(); } int operator <= (Complex Z1,Complex Z2) { return Z1.Abs() <= Z2.Abs(); } double Complex::Abs() { return sqrt(Real*Real+Imaginary*Imaginary); }

24

int main() { Complex X,Y(4.3,8.2),Z(3.3,1.1); cout<<"X: "; X.Print(); cout<<endl<<"Y: "; Y.Print(); cout<<endl<<"Z: "; Z.Print(); X = Y + 3.6; cout<<endl<<endl<<"X = Y + 3.6: "; X.Print(); cout<<" = "; Y.Print(); cout<<" + 3.6 "; X = 3.6 + Y; cout<<endl<<"X = 3.6 + Y: "; X.Print(); cout<<" = 3.6 + "; Y.Print(); X = 3.8 - Z; cout<<endl<<"X = 3.8 - Z: "; X.Print(); cout<<" = 3.8 - "; Z.Print(); X = Z - 3.8; cout<<endl<<"X = Z - 3.8: "; X.Print(); cout<<" = "; Z.Print(); cout<<" - 3.8 "; return 0; }

25

26

8.6 A NNG HA CC TON T MT NGI


Ton t + * & -> V d +c -c *c &c c-> Ton t ~ ! ++ -V d ~c !a ++c, c++ --c, c--

Ton t mt ngi ca lp c a nng ha nh mt hm thnh vin khng c tham s hoc nh mt hm khng thnh vin vi mt tham s; Tham s phi hoc l mt i tng lp hoc l mt tham chiu n i tng lp.

V d :thm ton t du tr mt ngi vo lp Complex

27

Thm vo nh ngha lp Complex dng sau Complex operator (); V phn nh ngha cc hm v ton t ca lp ta thm Complex Complex::operator - () { Complex Tmp; Tmp.R = -R; Tmp.I = -I; return Tmp; }

28

8.7 A NNG HA MT S TON T C BIT Trong phn ny chng ta s tm hiu cch ci t mt vi ton t c bit nh () [] ++ -- , = -> Ton t []: Khi ci t cc lp vector hoc chui k t, chng ta cn phi truy cp n tng phn t ca chng, trong ngn ng C/C++ c ton t [] truy cp n mt phn t ca mng. y l ton t hai ngi, c dng a[b] v khi a nng ton t ny th hm ton t tng ng phi l thnh vin ca mt lp. V d : a nng ha ton t [] truy cp n mt phn t ca vector.

29

#include <iostream.h> class Vector { private: int Size; int *Data; public: Vector(int S=2,int V=0); ~Vector(); void Print() const; int & operator [] (int I); }; Vector::Vector(int S,int V) { Size = S; Data=new int[Size]; for(int I=0;I<Size;++I) Data[I]=V; }

30

Vector::~Vector() { delete []Data; } void Vector::Print() const { cout<<"Vector:("; for(int I=0;I<Size;++I) cout<<Data[I]<<","; cout<<")"<<endl; } int & Vector::operator [](int I) { return Data[I]; }

hm ton t [] tr v mt tham chiu v ton t ny c th dng v tri ca php gn

31

int main() { Vector V(5,1); V.Print(); for(int I=0;I<5;++I) V[I]*=(I+1); V.Print(); V[0]=10; V.Print(); return 0; }

32

Ton t () Ton t () c dng gi hm, ton t ny gm hai ton hng: ton hng u tin l tn hm, ton hng th hai l danh sch cc tham s ca hm. Ton t ny c dng ging nh ton t [] v khi a nng ton t ny th hm ton t tng ng phi l thnh vin ca mt lp. V d : a nng ha ton t () truy cp n phn t ca ma trn.

33

#include <iostream.h> class Matrix { private: int Rows,Cols; int **Data; public: Matrix(int R=2,int C=2,int V=0); ~Matrix(); void Print() const; int & operator () (int R,int C); };

Matrix::Matrix(int R,int C,int V) { int I,J; Rows=R; Cols=C; Data = new int *[Rows]; int *Temp=new int[Rows*Cols]; for(I=0;I<Rows;++I) { Data[I]=Temp; Temp+=Cols; } for(I=0;I<Rows;++I) for(J=0;J<Cols;++J) Data[I][J]=V; } Matrix::~Matrix() { delete [] Data[0]; delete [] Data; }

34

35

void Matrix::Print() const { int I,J; for(I=0;I<Rows;++I) { for(J=0;J<Cols;++J) { cout.width(5); // canh l phi chiu di 5 k t cout<<Data[I][J]; } cout<<endl; } } int & Matrix::operator () (int R,int C) { return Data[R][C]; }

36

int main() { int I,J; Matrix M(2,3,1); cout<<"Matrix:"<<endl; M.Print(); for(I=0;I<2;++I) for(J=0;J<3;++J) M(I,J)*=(I+J+1); cout<<"Matrix:"<<endl; M.Print(); return 0; }

37

Ton t ++ v - Cn ch phn bit ++a v a++ c th phn bit c tin t v hu t khi a nng ha, ton t ++a (hoc --a) l ton t mt ngi, cn ton t a++ (hoc a--) c xem l ton t hai ngi trong ton hng th hai kiu int. V d : a nng ha ton t ++ v c phn bit tin t v hu t.

38

#include <iostream.h> class Point { private: int X,Y; public: Point(int A=0,int B=0); Point operator ++(); Point operator ++(int); //Hu t Point operator --(); //Tin t Point operator --(int); //Hu t void Print() const; };

39

Point::Point(int A,int B) { X = A; Y = B; } Point Point::operator++() { ++X; ++Y; return *this; } Point Point::operator++(int){ Point Tmp=*this; //Sao chp tng ang xt // vo tng tm thi trc khi thay i ++X; ++Y; return Tmp; }

40

Point Point::operator--() { --X; --Y; return *this; } Point Point::operator--(int) { Point Tmp=*this; //Sao chp i tng ang xt vo //i tng tm thi trc khi thay i --X; --Y; return Tmp; } void Point::Print() const { cout<<"X="<<X<<",Y="<<Y<<endl; }

41

int main() { Point P1(2,6),P2(5,8),P3,P4; cout<<"Point 1:"; P1.Print(); cout<<"Point 2:"; P2.Print(); cout<<"Point 3:"; P3.Print(); cout<<"Point 4:"; P4.Print(); P3=++P1; P4=P2++; cout<<"Point 1:"; P1.Print(); cout<<"Point 2:"; P2.Print(); cout<<"Point 3:"; P3.Print(); cout<<"Point 4:"; P4.Print(); return 0; }

42

Ton t xut << nh ngha hm ton cc:


ostream& operator << (ostream&, Class&);

class Point { public: Point (int x=0, int y=0) { Point::x = x; Point::y = y; } friend ostream& operator << (ostream& os, Point& p) { os<< ( << p.x << , << p.y << ); } // .. private: int x, y; };

void main() { Point p1(10,20), p2; cout<<Diem P1: << p1 << endl; cout<<Diem P2: << p2 << endl; }

Kt qu trn mn hnh ?

Chng 8

43

Ti nh ngha ton t nhp >>


nh ngha hm ton cc:
istream& operator >> (istream&, Class&);

class Point { public: Point (int x=0, int y=0) { Point::x = x; Point::y = y; } friend istream& operator >> (istream& is, Point& p) { cout<<Nhap x: ; is>>p.x; cout<<Nhap y: ; is>>p.y; } // .. private: int x, y; };

void main() { Point p1, p2; cout<<Nhap thong tin cho P1: \n; cin>>p1; cout<<Nhap thong tin cho P2: \n; cin>>p2; }

44

Khi to ngm nh
c nh ngha sn trong ngn ng:
VD: Point p1(10,20); Point p2 = p1;

S gy ra li (kt qu SAI) khi bn trong i tng c thnh phn d liu l con tr.
VD: Matrix m(5,6); Matrix n = m;

Li s xy ra do khi to ngm bng cch gn tng ng tng thnh phn.

Chng 8

45

Khi to ngm nh (cont..)


Khi lp c thnh phn d liu con tr, phi nh ngha hm Khi to sao chp

class Point { int x, y; public: Point (int =0; int =0 ); // Khong can thiet DN Point (const Point& p) { x= p.x; y = p.y; } // .. }; //

class Vector { // Vector(const Vector&);

}; Vector:: Vector (const Vector &m) {


Size = m.Size; Data=new int[Size]; for(int i=0;i<Size;++i) Data[i]=m.Data[i]; // sao chp phn t }

Chng 8

46

Gn ngm nh
c nh ngha sn trong ngn ng:
Gn tng ng tng thnh phn. ng khi i tng khng c d liu con tr. VD: Point p1(10,20); Point p2; p2 = p1;

Khi thnh phn d liu c con tr, bt buc phi nh ngha php gn = cho lp.
Hm thnh vin

class Vector { //. Vector& operator = (const Vector &m) { if (Size == m.Size) { // phi khp for (int i = 0; i < Size; ++i) // sao chp cc phn t data[i] = m.Data[i]; } return *this; } };

47

8.8 Case Study: Array class Arrays in C++


No range checking Cannot be compared meaningfully with == No array assignment (array names const pointers) Cannot input/output entire arrays at once
One element at a time

Example:Implement an Array class with


Range checking Array assignment Arrays that know their size Outputting/inputting entire arrays with << and >> Array comparisons with == and !=

48

8.8 Case Study: Array class Copy constructor


Used whenever copy of object needed
Passing by value (return value or parameter) Initializing an object with a copy of another
Array newArray( oldArray ); newArray copy of oldArray

Prototype for class Array


Array( const Array & ); Must take reference Otherwise, pass by value Tries to make copy by calling copy constructor Infinite loop

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Fig. 8.4: array1.h // Array class for storing arrays of integers. #ifndef ARRAY1_H #define ARRAY1_H #include <iostream> using std::ostream; using std::istream; class Array { friend ostream &operator<<( ostream &, const Array & ); friend istream &operator>>( istream &, Array & ); public: Array( int = 10 ); Array( const Array & ); ~Array(); int getSize() const;

49

Outline
array1.h (1 of 2)

// // // // return size

Most operators overloaded as member functions (except << default constructor and >>, which must be noncopy constructor destructor member functions). Prototype for copy constructor.

// assignment operator const Array &operator=( const Array & ); // equality operator bool operator==( const Array & ) const;

2003 Prentice Hall, Inc.


All rights reserved.

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

// inequality operator; returns opposite of == operator bool operator!=( const Array &right ) const { return ! ( *this == right ); // invokes Array::operator== } // end function operator!= // subscript operator for int &operator[]( int );

50

Outline
array1.h (2 of 2)

!= operator simply returns opposite of == operator. Thus, non-const objects returns lvalue only need to define the == operator.

// subscript operator for const objects returns rvalue const int &operator[]( int ) const; private: int size; // array size int *ptr; // pointer to first element of array }; // end class Array #endif

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Fig 8.5: array1.cpp // Member function definitions for class Array #include <iostream> using std::cout; using std::cin; using std::endl; #include <iomanip> using std::setw; #include <new> #include <cstdlib> #include "array1.h" // C++ standard "new" operator // exit function prototype // Array class definition

51

Outline
array1.cpp (1 of 7)

// default constructor for class Array (default size 10) Array::Array( int arraySize ) { // validate arraySize size = ( arraySize > 0 ? arraySize : 10 ); ptr = new int[ size ]; // create space for array

2003 Prentice Hall, Inc.


All rights reserved.

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; // initialize array } // end Array default constructor // copy constructor for class Array; // must receive a reference to prevent infinite recursion We must declare a new integer array Array::Array( const Array &arrayToCopy ) the objects do not point to the same : size( arrayToCopy.size ) memory. { ptr = new int[ size ]; // create space for array for ( int i = 0; i < size; i++ ) ptr[ i ] = arrayToCopy.ptr[ i ]; } // end Array copy constructor // destructor for class Array Array::~Array() { delete [] ptr; // reclaim array space

52

Outline
array1.cpp (2 of 7) so

// copy into object

} // end destructor

2003 Prentice Hall, Inc.


All rights reserved.

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

// return size of array int Array::getSize() const { return size; } // end function getSize // overloaded assignment operator; Want to avoid self-assignment. // const return avoids: ( a1 = a2 ) = a3 const Array &Array::operator=( const Array &right ) { if ( &right != this ) { // check for self-assignment // for arrays of different sizes, deallocate original // left-side array, then allocate new left-side array if ( size != right.size ) { delete [] ptr; // reclaim space size = right.size; // resize this object ptr = new int[ size ]; // create space for array copy } // end inner if

53

Outline
array1.cpp (3 of 7)

for ( int i = 0; i < size; i++ ) ptr[ i ] = right.ptr[ i ]; // copy array into object
} // end outer if

2003 Prentice Hall, Inc.


All rights reserved.

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

54
return *this; // enables x = y = z, for example

Outline
array1.cpp (4 of 7)

} // end function operator= // determine if two arrays are equal and // return true, otherwise return false bool Array::operator==( const Array &right ) const { if ( size != right.size ) return false; // arrays of different sizes for ( int i = 0; i < size; i++ ) if ( ptr[ i ] != right.ptr[ i ] ) return false; // arrays are not equal return true; // arrays are equal

} // end function operator==

2003 Prentice Hall, Inc.


All rights reserved.

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

// overloaded subscript operator for non-const Arrays // reference return creates an lvalue int &Array::operator[]( int subscript ) { // check for subscript out of range error integers1[5] calls if ( subscript < 0 || subscript >= size ) { integers1.operator[]( cout << "\nError: Subscript " << subscript << " out of range" << endl;

55

Outline
array1.cpp (5 of 7) 5 )

exit( 1 );
} // end if

// terminate program; subscript out of range

exit() (header <cstdlib>) ends the program.

return ptr[ subscript ]; // reference return } // end function operator[]

2003 Prentice Hall, Inc.


All rights reserved.

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141

// overloaded subscript operator for const Arrays // const reference return creates an rvalue const int &Array::operator[]( int subscript ) const { // check for subscript out of range error if ( subscript < 0 || subscript >= size ) { cout << "\nError: Subscript " << subscript << " out of range" << endl;

56

Outline
array1.cpp (6 of 7)

exit( 1 );
} // end if

// terminate program; subscript out of range

return ptr[ subscript ]; // const reference return } // end function operator[] // overloaded input operator for class Array; // inputs values for entire array istream &operator>>( istream &input, Array &a ) { for ( int i = 0; i < a.size; i++ ) input >> a.ptr[ i ]; return input; } // end function // enables cin >> x >> y;

2003 Prentice Hall, Inc.


All rights reserved.

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

57
// overloaded output operator for class Array ostream &operator<<( ostream &output, const Array &a ) { int i; // output private ptr-based array for ( i = 0; i < a.size; i++ ) { output << setw( 12 ) << a.ptr[ i ]; if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output output << endl; } // end for if ( i % 4 != 0 ) // end last line of output output << endl; return output; // enables cout << x << y;

Outline
array1.cpp (7 of 7)

} // end function operator<<

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

// Fig. 8.6: fig08_06.cpp // Array class test program. #include <iostream> using std::cout; using std::cin; using std::endl; #include "array1.h" int main() { Array integers1( 7 ); Array integers2;

58

Outline
fig08_06.cpp (1 of 3)

// seven-element Array // 10-element Array by default

// print integers1 size and contents cout << "Size of array integers1 is " << integers1.getSize() << "\nArray after initialization:\n" << integers1; // print integers2 size and contents cout << "\nSize of array integers2 is " << integers2.getSize() << "\nArray after initialization:\n" << integers2;

2003 Prentice Hall, Inc.


All rights reserved.

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

// input and print integers1 and integers2 cout << "\nInput 17 integers:\n"; cin >> integers1 >> integers2; cout << "\nAfter input, the arrays contain:\n" << "integers1:\n" << integers1 << "integers2:\n" << integers2; // use overloaded inequality (!=) operator cout << "\nEvaluating: integers1 != integers2\n"; if ( integers1 != integers2 ) cout << "integers1 and integers2 are not equal\n"; // create array integers3 using integers1 as an // initializer; print size and contents Array integers3( integers1 ); // calls copy constructor cout << "\nSize of array integers3 is " << integers3.getSize() << "\nArray after initialization:\n" << integers3;

59

Outline
fig08_06.cpp (2 of 3)

2003 Prentice Hall, Inc.


All rights reserved.

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

// use overloaded assignment (=) operator cout << "\nAssigning integers2 to integers1:\n"; integers1 = integers2; // note target is smaller cout << "integers1:\n" << integers1 << "integers2:\n" << integers2; // use overloaded equality (==) operator cout << "\nEvaluating: integers1 == integers2\n"; if ( integers1 == integers2 ) cout << "integers1 and integers2 are equal\n"; // use overloaded subscript operator to create rvalue cout << "\nintegers1[5] is " << integers1[ 5 ]; // use overloaded subscript operator to create lvalue cout << "\n\nAssigning 1000 to integers1[5]\n"; integers1[ 5 ] = 1000; cout << "integers1:\n" << integers1; // attempt to use out-of-range subscript cout << "\nAttempt to assign 1000 to integers1[15]" << endl; integers1[ 15 ] = 1000; // ERROR: out of range return 0; } // end main

60

Outline
fig08_06.cpp (3 of 3)

2003 Prentice Hall, Inc.


All rights reserved.

61
Size of array integers1 is 7 Array after initialization: 0 0 0 0 Size of array integers2 is 10 Array after initialization: 0 0 0 0 0 0

Outline
0 0 0

fig08_06.cpp output (1 of 3)

0 0

0 0

Input 17 integers: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 After input, the arrays contain: integers1: 1 2 5 6 integers2: 8 9 12 13

3 7 10 14

11 15

2003 Prentice Hall, Inc.


All rights reserved.

Evaluating: integers1 != integers2 integers1 and integers2 are not equal Size of array integers3 is 7 Array after initialization: 1 2 5 6 Assigning integers2 to integers1: integers1: 8 9 12 13 16 17 integers2: 8 9 12 13 16 17 Evaluating: integers1 == integers2 integers1 and integers2 are equal integers1[5] is 13

62

Outline
fig08_06.cpp output (2 of 3)

3 7

10 14

11 15

10 14

11 15

2003 Prentice Hall, Inc.


All rights reserved.

Assigning 1000 to integers1[5] integers1: 8 9 12 1000 16 17

63

Outline
10 14 11 15

fig08_06.cpp output (3 of 3)

Attempt to assign 1000 to integers1[15] Error: Subscript 15 out of range

2003 Prentice Hall, Inc.


All rights reserved.

64

8.11 Overloading ++ and - Increment/decrement operators can be overloaded


Add 1 to a Date object, d1

Prototype (member function)


Date &operator++(); ++d1 same as d1.operator++()

Prototype (non-member)
Friend Date &operator++( Date &); ++d1 same as operator++( d1 )

65

8.11 Overloading ++ and - To distinguish pre/post increment


Post increment has a dummy parameter
int of 0

Prototype (member function)


Date operator++( int ); d1++ same as d1.operator++( 0 )

Prototype (non-member)
friend Date operator++( Data &, int ); d1++ same as operator++( d1, 0 )

Integer parameter does not have a name


Not even in function definition

66

8.11 Overloading ++ and - Return values


Preincrement
Returns by reference (Date &)
lvalue (can be assigned)

Postincrement
Returns by value Returns temporary object with old value rvalue (cannot be on left side of assignment)

Decrement operator analogous

67

8.12 Case Study: A Date Class Example Date class


Overloaded increment operator
Change day, month and year

Overloaded += operator Function to test for leap years Function to determine if day is last of month

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

// Fig. 8.10: date1.h // Date class definition. #ifndef DATE1_H #define DATE1_H #include <iostream> using std::ostream;

68

Outline
date1.h (1 of 2)

class Date { friend ostream &operator<<( ostream &, const Date & ); public: Date( int m = 1, int d = 1, int y = 1900 ); // constructor void setDate( int, int, int ); // Note set difference the date between pre and post increment. Date &operator++(); // preincrement operator Date operator++( int ); // postincrement operator const Date &operator+=( int ); // add days, modify object bool leapYear( int ) const; bool endOfMonth( int ) const; // is this a leap year? // is this end of month? 2003 Prentice Hall, Inc.
All rights reserved.

23 24 25 26 27 28 29 30 31 32 33 34

69

private: int month; int day; int year; static const int days[]; void helpIncrement(); }; // end class Date #endif

Outline
date1.h (2 of 2)

// array of days per month // utility function

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

// Fig. 8.11: date1.cpp // Date class member function definitions. #include <iostream> #include "date1.h"

70

Outline
date1.cpp (1 of 5)

// initialize static member at file scope; // one class-wide copy const int Date::days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // Date constructor Date::Date( int m, int d, int y ) { setDate( m, d, y ); } // end Date constructor // set month, day and year void Date::setDate( int mm, int dd, int yy ) { month = ( mm >= 1 && mm <= 12 ) ? mm : 1; year = ( yy >= 1900 && yy <= 2100 ) ? yy : 1900;

2003 Prentice Hall, Inc.


All rights reserved.

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

// test for a if ( month == day = ( dd else day = ( dd

leap year 2 && leapYear( year ) ) >= 1 && dd <= 29 ) ? dd : 1; >= 1 && dd <= days[ month ] ) ? dd : 1;

71

Outline
date1.cpp (2 of 5)

} // end function setDate // overloaded preincrement operator Date &Date::operator++() { helpIncrement(); return *this; // reference return to create an lvalue

} // end function operator++ // overloaded postincrement operator; note that the dummy // integer parameter does not have a parameter name Date Date::operator++( int ) { Date temp = *this; // hold current state of object helpIncrement(); // return unincremented, saved, temporary object return temp; // value return; not a reference return } // end function operator++

Postincrement updates object and returns a copy of the original. Do not return a reference to temp, because it is a local variable that will be destroyed. Also note that the integer parameter does not have a name.
2003 Prentice Hall, Inc.
All rights reserved.

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

72 // add specified number of days to date const Date &Date::operator+=( int additionalDays ) { for ( int i = 0; i < additionalDays; i++ ) helpIncrement(); return *this; // enables cascading

Outline
date1.cpp (3 of 5)

} // end function operator+= // if the year is a leap year, return true; // otherwise, return false bool Date::leapYear( int testYear ) const { if ( testYear % 400 == 0 || ( testYear % 100 != 0 && testYear % 4 == 0 ) ) return true; // a leap year else return false; // not a leap year } // end function leapYear

2003 Prentice Hall, Inc.


All rights reserved.

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

// determine whether the day is the last day of the month bool Date::endOfMonth( int testDay ) const { if ( month == 2 && leapYear( year ) ) return testDay == 29; // last day of Feb. in leap year else return testDay == days[ month ]; } // end function endOfMonth // function to help increment the date void Date::helpIncrement() { // day is not end of month if ( !endOfMonth( day ) ) ++day; else

73

Outline
date1.cpp (4 of 5)

// day is end of month and month < 12 if ( month < 12 ) { ++month; day = 1; }
2003 Prentice Hall, Inc.
All rights reserved.

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

// last day of year else { ++year; month = 1; day = 1; } } // end function helpIncrement // overloaded output operator ostream &operator<<( ostream &output, const Date &d ) { static char *monthName[ 13 ] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; output << monthName[ d.month ] << ' ' << d.day << ", " << d.year; return output; // enables cascading

74

Outline
date1.cpp (5 of 5)

} // end function operator<< 2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

// Fig. 8.12: fig08_12.cpp // Date class test program. #include <iostream> using std::cout; using std::endl; #include "date1.h" // Date class definition

75

Outline
fig08_12.cpp (1 of 2)

int main() { Date d1; // defaults to January 1, 1900 Date d2( 12, 27, 1992 ); Date d3( 0, 99, 8045 ); // invalid date cout << "d1 is " << d1 << "\nd2 is " << d2 << "\nd3 is " << d3; cout << "\n\nd2 += 7 is " << ( d2 += 7 ); d3.setDate( 2, 28, 1992 ); cout << "\n\n d3 is " << d3; cout << "\n++d3 is " << ++d3; Date d4( 7, 13, 2002 ); 2003 Prentice Hall, Inc.
All rights reserved.

26 27 28 29 30 31 32 33 34 35 36 37 38 39

76

cout << << cout << cout << cout << << cout << cout <<

"\n\nTesting the preincrement operator:\n" " d4 is " << d4 << '\n'; fig08_12.cpp "++d4 is " << ++d4 << '\n'; (2 of 2) " d4 is " << d4; "\n\nTesting the postincrement operator:\n" " d4 is " << d4 << '\n'; "d4++ is " << d4++ << '\n'; " d4 is " << d4 << endl;

Outline

return 0; } // end main

2003 Prentice Hall, Inc.


All rights reserved.

d1 is January 1, 1900 d2 is December 27, 1992 d3 is January 1, 1900 d2 += 7 is January 3, 1993 d3 is February 28, 1992 ++d3 is February 29, 1992 Testing d4 is ++d4 is d4 is Testing d4 is d4++ is d4 is the preincrement operator: July 13, 2002 July 14, 2002 July 14, 2002 the postincrement operator: July 14, 2002 July 14, 2002 July 15, 2002

77

Outline
fig08_12.cpp output (1 of 1)

2003 Prentice Hall, Inc.


All rights reserved.