Download presentation
Presentation is loading. Please wait.
Published byBrittney Carter Modified over 9 years ago
1
1 Chapter 8 Composition
2
2 Outlines 8.1 Composition versus Inheritance 8.2 Using Composition 8.3 Constructing and Destroying Composed Classes 8.4 Combining Composition and Inheritance 8.5 Case Study: Computer System Configurator
3
3 8.1 Composition vs. Inheritance Code reusability can be promoted in C++ by establishing relationships between classes. A new kind of relationship between classes called composition. An AND gate is a type of gate, and a gate is a type of logic circuit. Therefore, an AND gate class is derived from a gate class and the gate class is derived from a logic circuit class. Sometimes an object is not a type or subgroup of another object.
4
4 AND->GATE->LC
5
5 Composition C++ provides another relationship between classes called composition, which is also known as a has ‑ a relationship. For example, a CPU is not a type of PC, howev er, a PC has a CPU as well as many other components. Therefore, a PC class could be composed of a CPU class and some other classes. A new class can be composed from as many existing classes and built ‑ in types as an application requires.
6
6 Has-a relationship
7
7 Class declaration To compose a class from existing classes, an object of each class should be declared as a member of the new class. Storage class, which is composed of the three classes Hard_Disk, RAM, and Floppy Class Storage//composed class { float capacity; Hard Disk hdst;//an object of the Hard Disk class RAM ramst;//an object of the RAM class Floppy fpst;//an object of the Floppy class Public: Storage(); ~Storage(); };
8
8 Composition Classes that are used to build a composed class can be referred to as subclasses and their objects as embedded objects, or subobjects. In addition to the three embedded objects, hdst, ramst, and fpst, the Storage class contains a built ‑ in type as well. The embedded objects are private members of the Storage class. They can be designed as public members as well.
9
9 8.2 Using Composition 1.//PROG8_1: Program demonstrates a composed class 2.// with embedded objects as public members. 3.#include 4.using namespace std; 5.class Pixel{ //subclass 6. int x, y; //x and y coordinates of a pixel 7.public: 8. Pixel(){ x=0; y=0; } 9. void set(int a, int b) { x=a; y=b; } 10. int getx() const { return x; } 11. int gety() const { return y; } 12.}; 13.class Rectangle{ //composed class as ** public member 14. int perimeter; 15.public: 16. Pixel p1, p2; //embedded objects as public members 17. Rectangle(){ perimeter=0; } 18. void getperim(); 19.};
10
10 1.void Rectangle::getperim() 2.{ 3. int x1 = p1.getx(); //Calls the embedded objects' 4. int x2 = p2.getx(); //member functions 5. int y1 = p1.gety(); 6. int y2 = p2.gety(); 7. cout<<"Top-left corner coordinates : ["; 8. cout<<x1<<','<<y1<<']'<<endl; 9. cout<<"Bottom-right corner coordinates : ["; 10. cout<<x2<<','<<y2<<']'<<endl; 11. cout<<"Perimeter = "<<(2*(x2-x1)+2*(y2-y1)); 12.} 13.int main() 14.{ 15. Rectangle r; //composed object 16. r.p1.set(5,5); //Using composed object to access 17. r.p2.set(10,10); //members of the embedded objects. 18. r.getperim(); 19. return 0; 20.}
11
11 Note The security of the subclass's private members is maintained, even if the embedded objects have public access in the composed class. Each level of objects or sub-objects is separated by a dot (.) separator.composed_object.subobject.subobject_m ember The composed class can only access public members of its subclass. Access to the private members of the subclass is limited to the members of that subclass. The public members of the subclass, in this case, cannot be accessed outside of the composed class through the objects of the composed class.
12
12
13
13 1.//PROG8_2: Program demonstrates composition with embedded 2.// objects as private members. 3.#include 4.using namespace std; 5.class Pixel { 6. int x, y; 7.public: 8. Pixel(){ x = 0; y = 0; } 9. void set(int a, int b) { x = a; y = b; } 10. int getx() const { return x; } 11. int gety() const { return y; } 12.}; 13.class Rectangle { 14. int perimeter; 15. Pixel p1, p2; //embedded objects as private members 16.public: 17. Rectangle(){ perimeter = 0; } 18. void getperim(); 19.};
14
14 1.void Rectangle::getperim() 2.{ 3. p1.set(5,5); //Calls the embedded objects' 4. p2.set(10,10); //interface functions 5. int x1 = p1.getx(); 6. int x2 = p2.getx(); 7. int y1 = p1.gety(); 8. int y2 = p2.gety(); 9. cout<<"Top-left corner coordinates : ["; 10. cout<<x1<<','<<y1<<']'<<endl; 11. cout<<"Bottom-right corner coordinates : ["; 12. cout<<x2<<','<<y2<<']'<<endl; 13. cout<<"Perimeter = "<<(2*(x2-x1)+2*(y2-y1)); 14.} 15.int main() 16.{ 17. Rectangle r; //Instantiates a composed object and 18. r.getperim(); //calls its interface function 19. return 0; 20.}
15
15
16
16 Note If the embedded objects are created as private members of the composed class, their public interface functions are used to communicate with the composed class. The interface between the classes and the rest of the program in this case is established through the public interface functions of the composed class. It makes the program more maintainable, simplifies its logic, and provides a safer interface. Safer, in this context, means that the embedded objects are hidden from the rest of the program and can only be accessed by the members of its composed class.
17
17 8.3CONSTRUCTING AND DESTROYING COMPOSED CLASSES If a class is composed from one or more subclasses, the subclass embedded objects will be constructed first when the composed class is instantiated. Use default constructor functions. If a subclass uses a non ‑ default constructor function with arguments, the programmer must define a composed class constructor with a constructor initialization list. If this is not done, the compiler may not be able to construct composed objects.
18
18 A constructor initialization list should be designed if the subclasses have constructors with arguments. The names of the embedded objects are used instead of the names of the base classes to pass values between constructors.
19
19 Format: composed ‑ constructor( parameter list ): subobj1(values1),subobj2(values2),...,subobjn(valuesn) { //body of the composed constructor } A parameter list of the composed class constructor should include all of the arguments needed to initialize the data members of the composed class, as well as the arguments needed to initialize its embedded objects.
20
20 Example Rectangle(int a, int b, int c, int d) : p1(a, b), p2(c, d) { perimeter = 0; } The constructors needed to initialize the p1 and p2 sub- objects are called before the execution of the body of the composed class constructor. It is logical because it is necessary to build the sub- objects first in order to build an overall composed class object. The order of the constructor calls is not affected by the order of the embedded objects in the constructor initialization list.
21
21 The same syntax can also be used if a class is composed of built ‑ in types, class Circuit { char * type; int quantity; float price; public: Circuit(char *t, int q, float p): type(t), quantity(q), price(p) };
22
22 1.//PROG8_3: Program demonstrates the order of the constructor and 2.// destructor calls when constructing and destroying a 3.// composed object. 4.#include 5.using namespace std; 6.class Speaker { //subclass #1 7. float impedance; 8.public: 9. Speaker(float imp) //constructor #1 10. { 11. impedance = imp; 12. cout<<"Constructing speaker."<<endl; 13. } 14. float getimp()const { return impedance; } 15. ~Speaker() //destructor #1 16. { 17. cout<<"Destroying speaker."<<endl; 18. } 19.};
23
23 1.class Amplifier { //subclass #2 2. float impedance; 3.public: 4. Amplifier(float imp ) //constructor #2 5. { 6. impedance = imp; 7. cout<<"Constructing amplifier."<<endl; 8. } 9. float getimp()const { return impedance;} 10. ~Amplifier() //destructor #2 11. { 12. cout<<"Destroying amplifier."<<endl; 13. } 14.};
24
24 1.class Stereo { //composed class 2. Speaker sp; //embedded object #1 3. Amplifier amp; //embedded object #2 4.public: 5. Stereo(float x, float y):sp(x), amp(y) 6. { //composed constructor 7. cout<<"Constructing stereo."<<endl; 8. } 9. void matching() //Compares the impedances 10. { 11. if(sp.getimp()==amp.getimp()) 12. cout<<"Impedances are matched."<<endl; 13. else 14. cout<<"Impedances are not matcheed."<<endl; 15. } 16. ~Stereo() //composed destructor 17. { 18. cout<<"Destroying stereo."<<endl; 19. } 20.};
25
25 1.main() 2.{ 3. Stereo st(8, 8); //composed object 4. st.matching(); 5. return 0; 6.}
26
26 Please note that the output of PROG8 3 will not change even if the order of the embedded objects is changed in the constructor initialization list as follows:; Stereo(float x, float y): amp(x), sp(y) { cout«"Constructing stereo."« endl; }
27
27 A constructor of a composed class can also take objects as arguments. Doing this results in a much shorter list of arguments, whereas the constructors of the embedded objects require many individual arguments. A composed class can contain pointers to sub- objects as members. This class may use its constructor function to dynamically allocate sub-objects and store their addresses in the member pointers. Note that the composed class destructor must free memory dynamically allocated by the constructor.
28
28 1.//PROG8_4: Program demonstrates a composed class containing 2.// pointers to subobjects as members. 3.#include 4.using namespace std; 5.class Speaker { //subclass #1 6. float impedance; 7.public: 8. Speaker() //constructor #1 9. { 10. cout<<"Constructing speaker."<<endl; 11. } 12. void setimp(float imp) { impedance=imp; } 13. float getimp()const { return impedance; } 14. ~Speaker() //destructor #1 15. { 16. cout<<"Destroying speaker."<<endl; 17. } 18.};
29
29 1.class Amplifier { //subclass #2 2. float impedance; 3.public: 4. Amplifier() //constructor #2 5. { 6. cout<<"Constructing amplifier."<<endl; 7. } 8. void setimp(float imp) { impedance=imp; } 9. float getimp()const { return impedance; } 10. ~Amplifier() //destructor #2 11. { 12. cout<<"Destroying amplifier."<<endl; 13. } 14.};
30
30 1.class Stereo { //composed class 2. Speaker *ptsp; //pointer to subobject #1 3. Amplifier *ptamp; //pointer to subobject #2 4.public: 5. Stereo(Speaker &s, Amplifier &a) 6. { //composed constructor 7. ptsp=new Speaker; 8. ptamp=new Amplifier; 9. *ptsp=s; 10. *ptamp=a; 11. cout<<"\tConstructing stereo."<<endl; 12. } 13. void matching() //Compares the impedances 14. { 15. if(ptsp->getimp()==ptamp->getimp()) 16. cout<<"Impedances are matched."<<endl; 17. else 18. cout<<"Impedances are not matcheed."<<endl; 19. }
31
31 1. ~Stereo() //composed destructor 2. { 3. delete ptsp; 4. delete ptamp; 5. cout<<"\tDestroying stereo."<<endl; 6. } 7.}; 8.int main() 9.{ 10. Amplifier a; 11. a.setimp(8); 12. Speaker s; 13. s.setimp(8); 14. Stereo st(s, a); //composed object 15. st.matching(); 16. return 0; 17.}
32
32 Output
33
33 8.4 COMBINING INHERITANCE AND COMPOSITION
34
34 1.//PROG8_5: Program demonstrates a use of inheritance //and 2.//composition combined together to build a complex class. 3.#include 4.using namespace std; 5.class Pixel { //subclass 6. int x, y; 7.public: 8. Pixel(int a, int b) //constructor 9. { 10. x = a; 11. y = b; 12. cout<<"SubConstructor"<<" x="<<x<<" y="<<y<<endl; 13. } 14. ~Pixel(){cout<<"SubDestructor"<<endl;} //destructor 15.};
35
35 1.class RecShape { //base class protected: 2. int lg, wd; 3.public: 4. RecShape(int l, int w) //constructor 5. { 6. lg = l; 7. wd = w; 8. cout<<"BaseConstructor"<<" lg="<<lg<<" wd="<<wd<<endl; 9. } 10. ~RecShape(){cout<<"BaseDestructor"<<endl;} //destructor 11.};
36
36 1.class Rectangle:public RecShape { //derived & composed class 2. int perimeter; 3. Pixel p1, p2; //subobjects 4.public: 5. Rectangle(int x1,int y1,int x2,int y2): //constructor 6. RecShape(x2-x1,y2-y1),p1(x1,y1),p2(x2,y2) 7. { 8. perimeter = 0; 9. cout<<"CombConstructor"<<" x1="<<x1<<" y1="<<y1; 10. cout<<" x2="<<x2<<" y2="<<y2<<endl; 11. } 12. void getperim() 13. { 14. cout<<"Perimeter = "<<(2*lg + 2*wd)<<endl; 15. } 16. ~Rectangle(){cout<<"CombDestructor"<<endl;} //destructor 17.};
37
37 int main() { Rectangle r(5,5,10,10); r.getperim(); return 0; }
38
38
39
39
40
40
41
41
42
42 CASE STUDY: COMPUTER SYSTEM CONFIGURATOR INPUT/OUTPUT Input: – A selection of parts from the menu options offered –A choice of one of the following options: Display the current system configuration Change a part Exit the program output: –A list of all the parts selected, including the cost of each part and the total cost.
43
43 //CASEST8: The program demonstrates a practical use of // composition to configure a computer system. #include using namespace std; class CPU //Subclass CPU { char *bcpu[3]; //CPU options float pcpu[3]; //costs of CPU options public: CPU() { //CPU constructor bcpu[0]="Pentium III 866 MHz "; bcpu[1]="Pentium IV 1.4 GHz "; bcpu[2]="Pentium IV 2.0 GHz "; pcpu[0]=150; pcpu[1]=270; pcpu[2]=450; } friend ostream &operator <<(ostream &out, CPU &a); void select_cpu(char *temp[1], float &cost); };
44
44 ostream &operator <<(ostream &out, CPU &a) { out<<"\n\n CPU \t\t\t\tCOST\n" ; out<<"-------------------------------------\t\t\t------- \n"; for(int i = 0; i<3; i++) { out<<setiosflags(ios::left | ios::fixed)<<setprecision(2); out<<(i+1)<<") "<<setw(64)<<a.bcpu[i]; out<<"\t$"<<a.pcpu[i]<<endl; out<<'\n'; } return out; } void CPU::select_cpu(char *temp[1], float &cost) //Selects a CPU { int select; cout<<'\n'; do{ cout "; cin>>select; }while((select 3)); temp[0] = bcpu[select-1]; cost = pcpu[select-1]; }
45
45 class RAM { //Subclass RAM char *bmem[3]; //RAM options float pmem[3]; //costs of RAM options public: RAM() { //RAM constructor bmem[0]="64 MB "; bmem[1]="128 MB "; bmem[2]="256 MB "; pmem[0]=39.99; pmem[1]=68; pmem[2]=152; } friend ostream &operator <<(ostream &out, RAM b); void select_ram(char *temp[1], float &cost); }; ostream &operator <<(ostream &out, RAM b) //Displays RAM options { out<<"\n\n RAM \t\t\t\tCOST\n" ; out<<"------------------------------------\t\t\t------- \n"; for(int i=0; i<3; i++) { out<<setiosflags(ios::left | ios::fixed)<<setprecision(2); out<<(i+1)<<")"<<setw(62)<<b.bmem[i]; out<<"\t$"<<b.pmem[i]<<endl; out<<'\n'; } return out; }
46
46 void RAM::select_ram(char *temp[1], float &cost) //Selects a RAM { int select; cout<<"\n"; do{ cout "; cin>>select; }while((select 3)); temp[0] = bmem[select-1]; cost = pmem[select-1]; } class Hard_Drive { //Subclass Hard_Drive char *bhd[4]; float phd[4]; public: Hard_Drive() { bhd[0]="10.0 GB "; bhd[1]="15.3 GB"; bhd[2]="30.0 GB"; bhd[3]="40.0 GB"; phd[0]=110; phd[1]=124; phd[2]=174; phd[3]=220; } friend ostream &operator <<(ostream &out, Hard_Drive &c); void select_hdrive(char *temp[1], float &cost); };
47
47 ostream &operator <<(ostream &out, Hard_Drive &c) { out<<"\n\n HARD DRIVE \t\t\t\tCOST\n" ; out<<"-------------------------------------\t\t\t------- \n"; for(int i=0; i<4; i++) { out<<setiosflags(ios::left | ios::fixed)<<setprecision(2); out<<(i+1)<<") "<<setw(62)<<c.bhd[i]; out<<"\t$"<<c.phd[i]<<endl; out<<'\n'; } return out; } void Hard_Drive::select_hdrive(char *temp[1], float &cost) { int select; cout<<'\n'; do{ cout "; cin>>select; }while((select 4)); temp[0] = bhd[select-1]; cost = phd[select-1]; }
48
48 class PC { //Composed class char *parts[3]; //parts selected by the user float pcost[3]; //costs of the selected parts float total; //total cost of the system CPU cpu; //subobjects RAM ram; Hard_Drive hd; public: PC(); void display_cpu() { cout<<cpu; cpu.select_cpu(& parts[0], pcost[0]); } void display_mem() { cout<<ram; ram.select_ram(& parts[1], pcost[1]); } void display_hdrive() { cout<<hd; hd.select_hdrive(& parts[2], pcost[2]); } friend ostream &operator <<(ostream &out, PC a); };
49
49 PC::PC() //PC constructor { total=0; for(int i=0;i<3;i++) { parts[i] = "Not Selected"; pcost[i] = 0; } ostream &operator <<(ostream &out, PC a) { //Displays the system chosen and total cost for(int i=0;i<3;i++) a.total = a.total + a.pcost[i]; out<<setiosflags(ios::left | ios::fixed)<<setprecision(2); out<<" PART TYPE \t\t\tCOST\n "; out<<"-----------------------------------\t\t\t------"<<endl; out<<'\n'<<setw(15)<<"CPU:"<<setw(54)<<a.parts[0]; out<<"\t$"<<a.pcost[0]<<endl; out<<'\n'<<setw(15)<< "RAM:"<<setw(54)<<a.parts[1]; out<<"\t$"<<a.pcost[1]<<endl; out<<'\n'<<setw(15)<<"Hard drive:"<<setw(54)<<a.parts[2]; out<<"\t$"<<a.pcost[2]<<endl; out $"; out<<a.total<<endl; return out ; }
50
50 char menu() { char selection; cout<<"\n\n\n \t\t\t Computer System "<<endl; cout<<"\t\t-------------------------------------------\n\n"; cout<<"\t\ta) Select CPU \n"; cout<<"\t\tb) Select RAM \n"; cout<<"\t\tc) Select Hard Drive\n"; cout<<"\t\td) Display the system and total cost\n"; cout<<"\t\tx) Exit\n\n"; cout "; cin>> selection; return selection; }
51
51 int main() { char selection; PC computer; //Composed object do { selection=menu(); switch(selection) { case 'a': computer.display_cpu(); break; case 'b': computer.display_mem(); break; case 'c': computer.display_hdrive(); break; case 'd': cout<<" The system chosen : \n\n"; cout<<computer; break; case 'x': cout<<"\n\n\n\t\tEnd of program."; break; default: cout<<"\n\t Incorrect input! "; } } while(selection!='x'); return 0; }
52
52
53
53
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.