COEN244: Class composition Aishy Amer Electrical & Computer Engineering Outline Introduction Initializing composite objects Constant data members: where to initialize Composite classes share objects? Member initalization list Objects as members of their own class? Reference to objects Pointers to objects Static objects Container class of components Nested classes Composition versus inheritance: a case study “Circle/Point” c A. Amer Class composition 1
69
Embed
Aishy Amer - users.encs.concordia.caamer/teach/coen244/notes/composition.pdf · / / 3. Creation of Rectangle object rec / / 3.1. creation of pt1 and pt2 , calling Point default constructors
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
COEN244: Class composition
Aishy Amer
Electrical & Computer Engineering
OutlineIntroduction
Initializing composite objects
Constant data members: where to initialize
Composite classes share objects?
Member initalization list
Objects as members of their own class?
Reference to objects
Pointers to objects
Static objects
Container class of components
Nested classes
Composition versus inheritance: a case study “Circle/Point”
Poin t p1 (20 ,40) , p2 (70 ,90 ) ; / / top− l e f t , bottom−r i g h t cornersRectangle rec ( p1 , p2 , 4 ) ; / / cons t ruc t rec
/ / a l t e r n a t i v e l y ( bad choice )/ / c lass Rectangle / / a composi t ion o f po in t s ?/ / {/ / p r i v a t e :/ / i n t x1 , y1 , x2 , y2 ; / / top− l e f t , bottom−r i g h t corner po in t s/ / i n t th ickness ; / / th ickness o f the rec tang le border/ / p u b l i c :/ / Rectangle ( const i n t xx1 , const i n t yy1 ,
const i n t xx2 , const i n t yy2 , i n t width =1) ;
Wasted callsPoin t p1 (20 ,40) , p2 (70 ,90 ) ;/ / 1 . p1 and p2 created , Po in t genera l cons t ruc to r c a l l e d
Poin t po i n t (100 ,120) ;/ / 2 . po i n t i s created , Po in t genera l cons t ruc to r c a l l e d
Rectangle rec ( p1 , p2 , 4 ) ;/ / 3 . Creat ion o f Rectangle ob jec t rec/ / 3 . 1 . c rea t i on o f pt1 and pt2 , c a l l i n g Po in t d e f a u l t cons t ruc to r s/ / Note : Po in t d e f a u l t cons t ruc to r s are c a l l e d before the/ / the Rectangle ob jec t i s created !/ / 3.2 assignment opera tor i s c a l l e d
→ For large composite objects, the process of creation canbecome quit wasteful. What to do?
The solution: Member initialization list (MIL)
Rectangle : : Rectangle ( const Poin t& p1 , const Poin t& p2 , i n t w): th ickness (w) , pt1 ( p1 ) , pt2 ( p2 ) / / i n i t i a l i z a t i o n l i s t
Saving callsPoin t p1 (20 ,40) , p2 (70 ,90 ) ;/ / 1 . p1 and p2 created , Po in t genera l cons t ruc to r c a l l e d
Poin t po i n t (100 ,120) ;/ / 2 . po i n t i s created , Po in t genera l cons t ruc to r c a l l e d
Rectangle rec ( p1 , p2 , 4 ) ;/ / 3 . Creat ion o f Rectangle ob jec t rec/ / 3 . 1 . pt1 and pt2 created , Po in t copy cons t ruc to r c a l l e d/ / 3.2 No assignment opera tor i s c a l l e d ! Saving !
The purpose of the member initialization list is to avoida call to the default constructor of the component classbefore the call to the composite class constructor
The member initialization list replaces the call
to the default constructor of the component class
with the call to the constructor specified in the initialization list
Many usage of "const":const i n t x ; / / constant i n tx = 2; / / i l l e g a l − can ’ t modify x
const i n t ∗ pX ; / / changeable p o i n t e r to constant i n t∗pX = 3; / / i l l e g a l − can ’ t use pX to modify an i n tpX = &someOtherIntVar ; / / l e g a l − pX can po in t somewhere e lse
i n t ∗ const pY ; / / constant p o i n t e r to changeable i n t∗pY = 4; / / l e g a l − can use pY to modify an i n tpY = &someOtherIntVar ; / / i l l e g a l − can ’ t make pY po in t anywhere e lse
const i n t ∗ const pZ ; / / const p o i n t e r to const i n t∗pZ = 5; / / i l l e g a l − can ’ t use pZ to modify an i n tpZ = &someOtherIntVar ; / / i l l e g a l − can ’ t make pZ po in t anywhere e lse
i n t y ;const i n t ∗ pConstY = &y ; / / l e g a l − but can ’ t use pConstY to modify yi n t ∗ pMutableY = &y ; / / l e g a l − can use pMutableY to modify y∗pMutableY = 42;
const i n t x ; / / x cannot be modi f ied
const i n t ∗ pX = &x ; / / pX i s the address o f a const i n t/ / and can ’ t be used to change an i n t
∗pX = 4; / / i l l e g a l − can ’ t use pX to change an i n t
i n t ∗ p I n t ; / / address o f normal i n tp I n t = pX ; / / i l l e g a l − cannot conver t from const i n t ∗ to i n t ∗
i n t ∗ p I n t ; / / address o f a normal i n tp I n t = &x ; / / i l l e g a l − cannot conver t from const i n t ∗ to i n t ∗
private :Po in t pt1 ;Po in t pt2 ;i n t th i ckness ;const double weight ; / / weight o f one u n i t o f area
public :Rectangle ( const Poin t& p1 , const Poin t& p2 , double wt , i n t width =1) ;
. . . .} ;
Rectangle : : Rectangle ( const Poin t& p1 , const Poin t& p2 , double wt , i n t width ): th ickness ( width ) , pt1 ( p1 ) , pt2 ( p2 ) , weight ( wt )/ / i n i t i a l i z a t i o n o f weight ( wt ) here i s mandatory
void set ( i n t a , i n t b , i n t c ) {/ / s i ze=a ; / / ∗∗∗TRY IT ∗∗∗∗ : uncomment t h i s l i n e to t e s t/ / so you want to change s ize ?/ / Well , s ince s ize i s constant the compi ler w i l l not l e t t h i s go/ / cons t_ tes t . cpp : 5 6 : assignment o f read−only member ‘ MyClass : : s i ze ’hours = b ;minutes = c ;
}
void operator = ( const MyClass &c ) {hours = c . hours ;minutes=c . minutes ;/ / s i ze = c . s ize ; / / ∗∗∗TRY IT ∗∗∗∗ : uncomment t h i s l i n e to t e s t/ / the compi ler w i l l not agree ! ! s i ze i s const => cannot be changed !/ / E r ro r : assignment o f read−only member ‘ MyClass : : s i ze ’
MyClass mc(5 ,10 ,60 ) ;/ / w i th t h i s you are dec la r i ng & i n i t i a l i z i n g/ / the ob jec t mc i n c l u d i n g hours , minutes and s ize ./ / They are being created ( " cons t ruc ted " ) w i th a s p e c i f i e d value ./ / Thus they are being i n i t i a l i z e d . I f you change t h e i r/ / value l a t e r w i th opera tor = t h a t i s an assignment ./ / l i k e mc=mc1 ;mc. p r i n t ( ) ; / / p r i n t s 5 ,10 ,60mc. set ( 6 , 5 , 7 ) ;mc. p r i n t ( ) ; / / p r i n t s 6 ,5 ,60
MyClass mc1(15 ,20 ,70) ;/ / so you want to assign mc1 to mc/ / t h i s imp l i es you would change the const data member s ize ! ! !mc=mc1 ; / / s i ze i s not / cannot be changed !mc. p r i n t ( ) ; / / p r i n t s 15 ,20 ,60
Recall: all references in C++ are constant:1. they cannot change after they are initialized2. but their content can change
Hence,reference data members must be initialized only in a memberinitialization list
Note:Point& pt1;→ pt1 is a reference (an alias) that cannot change but itscontent can be changedconst Point& pt1;→ pt1 is a reference that cannot change; its contentscannot change either
Po in t& pt1 ; / / shared : re ference cannot be changedPoin t& pt2 ; / / shared : re ference cannot be changedi n t th i ckness ; / / th i ckness o f the rec tang le borderconst double weight ; / / weight o f one u n i t o f area
public :Rectangle ( const Poin t& p1 , const Poin t& p2 , double wt , i n t width =1) ;. . . .
Po in t ∗pt1 ; / / can be shared and changedPoin t ∗pt2 ;i n t th i ckness ; / / th i ckness o f the rec tang le borderconst double weight ; / / weight o f one u n i t o f area
public :Rectangle ( const Poin t∗ p1 , const Poin t∗ p2 , double wt , i n t width =1) ;. . . .
/ / pt1 ( p1 ) not mandatory here/ / Note : pt1 ( p1 ) i s p o i n t e r i n i t i a l i z a t i o n −− not copy cons t ruc to r/ / You may pass Po in te rs as not const ; Then they can be changed{ }
When the initialization procedure is complexdata = new Sample ∗ [MAX_ELEMENT ] ; / / Two dimensional a r rayfor ( unsigned i n t i = 0 ; i < MAX_ELEMENT ; i ++)data [ i ] = new Sample [MAX_ELEMENT ] ;
When there is an important comment to make before aparticular initialization line
His to r y ( ) : s i ze ( 3 ) , count ( 0 ) , i dx ( 0 ) {/ / The f o l l o w i n g l i n e i s the source o f BUG 3876data = new Sample [MAX_ELEMENT ] ;i f ( data == NULL) {cout << ’ ’No memory a l l o c a t e d ’ ’ <<endl ; e x i t ( 1 ) ;
}cout << ’ ’ user created defaul t cons t ruc to r o f H i s to r y c a l l e d ’ ’ <<endl ;
/ / An ob jec ts as member o f i t s own c lassclass Poin t {
private :i n t x , y ; / / p r i v a t e coord ina tesPoin t o r i g i n ; / / can I do t h i s ?
. . .} ;
Po in t p ; / / P i s created means/ / memory f o r x and y i s a l l o c a t e d/ / memory f o r o r i g i n i s a l l o c a t e d/ / memory f o r x and y of o r i g i n i s a l l o c a t e d/ / memory f o r o r i g i n o f o r i g i n i s a l l o c a t e d . ./ / . . . e tc . i n f i n i t e recu rs i ve loop !
→ (non-static) objects as members of their own class aredisallowed
Reference to objects as members of their own class?
Poin t ∗p=0; / / p set to n u l lPoin t ∗p = new Poin t (∗p , 8 0 , 9 0 ) ; / / a l l o c a t e memory and set to 80 ,90Poin t p1 ( p ) ; / / ∗p i s used as the o r i g i n f o r p1
→ Do not use (non-static) objects as members of their own classunless you have toBut what is the solution then?
i n t Poin t : : count = 0 ; / / i n i t i a l i z a t i o nPoin t Po in t : : o r i g i n (640 ,0 ) ; / / i n i t i a l i z a t i o n/ / ou tput : ’ Created : x=640 y=0 count =1 ‘
cout << " Number o f po in t s : " << Po in t : : q u a n t i t y ( ) << endl ;/ / ou tput : Number o f po in t s : 1
Poin t p1 , p2 (30 ) , p3 (50 ,70 ) ;/ / ou tput : 0 ,0 ,2 30 ,0 ,3 and 50 ,70 ,4
cout << " Number o f po in t s : " << p1 . q u a n t i t y ( ) << endl ;/ / ou tput : number o f po in t s : 4/ / Output from hidden c a l l s :/ / destroyed 50 ,70 destroyed 30 ,0 destroyed 0 ,0/ / But why ‘ destroyed 640 ,0 ’ i s not output ?/ / ==> s t a t i c data are destroyed a f t e r the program termina te
void His to r y : : add ( double s ) {i f ( count == s ize ) {
s ize = s ize ∗ 2; / / double s ize i f out o f spaceSample ∗p = new Sample [ s ize ] ;i f ( p == NULL)
{ cout << " Out o f memory \ n " ; e x i t ( 1 ) ; } / / t e s t f o r successfor ( i n t i =0; i < count ; i ++)
p [ i ] = data [ i ] ; / / copy e x i s t i n g elementsdelete [ ] data ; / / de le te e x i s t i n g ar raydata = p ; / / rep lace i t w i th new ar raycout << " new s ize : " << s ize << endl ; / / debugging p r i n t
}data [ count ++ ] . se t ( s ) ; / / use next space a v a i l a b l e
double a [ ] = {3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 } ; / / i npu t dataHis to r y h ;for ( i n t i =0; i < 9 ; i ++)
h . add ( a [ i ] ) ; / / add h i s t o r ycout << " \ n Measurement h i s t o r y : " << endl << endl ;h . g e t F i r s t ( ) ; / / work i s pushed updo {
cout << " " << h . getComponent ( ) . get ( ) ;/ / p r i n t each component
} while ( h . getNext ( ) ) ;h . average ( ) ;
/ / Output :new s ize : 6new s ize : 12Measurement h i s t o r y : 3 5 7 11 13 17 19 23 29Average : 14.1111
Composition: the existence of a "has-a" relationshipaggregate objects in a class
Inheritance: the existence of a “is-a” relationship conceptuallyconnect classes in an inheritance hierarchy
In most problems, inheritance is very useful and should beoften considered, however,
Inheritance forces the client programmer to learn aconsiderable amount about the server design, speciallywhen the hierarchy is tallDependencies between classes in inheritance are verystrong
Composition is conceptually simpler & links between classesare not as strong
Composition is, in general, easier to maintain
Choice depends on degree of similarity between relatedclasses
If the number of common methods is small & the number ofmethods to be is large, composition is a good alternative
If a “is-a” relationship is not clear then use composition:A Rectangle "has a" Point but it is not a Point;A Cylinder "has a" Circle or "is a" Circle?An Address "is a" Name or "has a" Name?
/ / L i s t i n g 14.2 code reuse through c lass composi t ionclass C i r c l e { / / o r i g i n a l code f o r reuse
protected : / / i n h e r i t a n c e i s one of the opt ionsdouble rad ius ; / / i n t e r n a l data
public :s t a t i c const double PI ; / / i t must be i n i t i a l i z e dC i r c l e ( double r ) ; / / convers ion cons t ruc to rdouble getLength ( ) const ; / / compute c i rcumferencedouble getArea ( ) const ; / / compute areadouble getRadius ( ) const ;void set ( double r ) ; / / change s ize
} ;const double C i r c l e : : PI = 3.1415926536;
class Cy l inder { / / new c lass Cy l inderprotected :
C i r c l e c ; / / no PI , no rad iusdouble he igh t ; / / new code
public :Cy l inder ( double r , double h ) : c ( r ) / / i n i t i a l i z e r l i s t ( no PI )
{ he igh t = h ; }double getLength ( ) const { return c . getLength ( ) ; } / / from c lass C i r c l edouble getRadius ( ) const { return c . getRadius ( ) ; } / / from c lass C i r c l evoid set ( double r ) { c . se t ( r ) ; } / / from c lass C i r c l edouble getVolume ( ) const / / no getArea ( )
{double rad ius = c . getRadius ( ) ;return C i r c l e : : PI ∗ rad ius ∗ rad ius ∗ he igh t ;
i n t main ( ) {Cy l inder cy l1 ( 2 . 5 , 6 . 0 ) , cy l2 ( 5 . 0 , 7 . 5 ) ; / / i n i t i a l i z e datadouble l eng th = cy l1 . getLength ( ) ; / / s i m i l a r to C i r c l ecy l1 . se t ( 3 . 0 ) ;double diam = 2 ∗ cy l1 . getRadius ( ) ; / / no c a l l to getArea ( )double vo l = cy l2 . getVolume ( ) ; / / not i n C i r c l ecout << " Circumference of f i r s t c y l i n d e r : " << leng th << endl ;cout << " Volume of the second c y l i n d e r : " << vo l << endl ;cout << " Diameter o f the f i r s t c y l i n d e r : " << diam << endl ;return 0;}
/ / L i s t i n g 14.3 code reuse through i n h e r i t a n c eclass C i r c l e { / / o r i g i n a l code f o r reuse
protected : / / i n h e r i t a n c e i s one of the opt ionsdouble rad ius ; / / i n t e r n a l data
public :s t a t i c const double PI ; / / i t must be i n i t i a l i z e dC i r c l e ( double r ) ; / / convers ion cons t ruc to rdouble getLength ( ) const / / compute c i rcumference
{ return 2 ∗ PI ∗ rad ius ; }double getArea ( ) const ; / / compute areadouble getRadius ( ) const ;void set ( double r ) ; / / change s ize
} ;const double C i r c l e : : PI = 3.1415926536;
i n t main ( ) {Cy l inder cy l1 ( 2 . 5 , 6 . 0 ) , cy l2 ( 5 . 0 , 7 . 5 ) ; / / i n i t i a l i z e datadouble l eng th = cy l1 . getLength ( ) ; / / s i m i l a r to C i r c l ecy l1 . se t ( 3 . 0 ) ;double diam = 2 ∗ cy l1 . getRadius ( ) ; / / no c a l l to getArea ( )double vo l = cy l2 . getVolume ( ) ; / / not i n C i r c l ecout << " Circumference of f i r s t c y l i n d e r : " << leng th << endl ;cout << " Volume of the second c y l i n d e r : " << vo l << endl ;cout << " Diameter o f the f i r s t c y l i n d e r : " << diam << endl ;return 0;
}/ / which Const ruc torRectangle ( Po in t& q , . . . ) { p=q ; . . . } / / = d e f a u l t cons t r . +assignment op/ / orRectangle ( Po in t& q , . . . ) : p ( q ) { . . . } / / copy cons t ruc to r
/ / What i s i n a member i n i t i a l i z a t i o n l i s t ?