"C + + Programming thought" chapter 13th inheritance and combination (original code + exercise + solution)

Source: Internet
Author: User

I. Related knowledge

Use a class that someone else has already created and debugged:
The key is to use the class instead of changing the code that already exists. This chapter will cover two ways to do this. The first approach is straightforward: simply create a new class that contains an existing class object, called a combination, because the new class is composed of objects that already exist in the class.
The second method is more ingenious, creating a new class as a type of an existing class, taking the form of an existing class, adding code to it, but not modifying it. This interesting activity is called inheritance, where a lot of work is done by the compiler. Inheritance is the cornerstone of object-oriented programming, and there is another meaning that will be explored in the next chapter.
For composition and inheritance (it is felt that they are methods that produce new types by existing types), they are similar in syntax and behavior. In this chapter, the reader will learn about these code reuse mechanisms.

Two. Related code

1.

<span style= "FONT-SIZE:18PX;" ><strong>/*useful.cpp*/#ifndef useful_h_#define useful_h_class x{int i;enum{factor = one};p ublic:x () {i = 0;} void set (int i) {i = i;} int read () Const{return I;} int Permute () {Return i = i * factor;}}; #endif </strong></span>

2.

<span style= "FONT-SIZE:18PX;" ><strong>/*compose.h*///in this class, numeric members are private, so it is absolutely safe to embed an object of type X inside a new//class as a common object. #include "useful.h" class Y{int i;public:x X; Y () {i = 0;} void f (int i) {i = i;} int g () const{return I;}; int main () {Y y;y.f (+); Y.x.set (PNS); return 0;} </strong></span>

3.

<span style= "FONT-SIZE:18PX;" ><strong>/* the public interface function for the new class, which contains the use of the embedded object, but does not have to mimic the interface of the embedded object. *//*compose2.h*///here, the execution of the Permute () function invokes the interface of X, and the other member functions of X are also called in the member function of Y. #include "useful.h" class y{int I; X x;public:y () {i = 0;} void f (int i) {i = I;x.set (i);} int g () const{return I * X.read ();} void Permute () {X.permute ();}}; int main () {Y y;y.f (+); Y.permute (); return 0;} </strong></span>

4.

<span style= "FONT-SIZE:18PX;" ><strong>/*inherit.cpp*/#include "useful.h" #include <iostream.h>class y:public x{int i;public:y () {i = 0;} int change ()//In Change (), the base class Permute () function is called, and the derived class has direct access to all public base class Functions {i = Permute (); return i;} void set (int I)//The Set () function in a derived class redefined the set () function in the base class///This is, if the function read () and Permute () are called for the object of type Y, the resulting base class version of these functions//(Can be in main () Seen in the show). But if you call set () for object Y, you get a redefined version. This means that if we do not like to get the base class version of a function in succession, we can change it (and also add a new letter//number, for example, changes ()). {i = i; X::set (I);}}; int main () {cout << sizeof (x) = "<< sizeof (x) << endl;cout <<" sizeof (Y) = "<< sizeof (Y) & lt;< Endl; Y D;d.change ();D. Read ();D. Permute ();D. Set (n); return 0;} </strong></span>

5.

<span style= "FONT-SIZE:18PX;" ><strong>/*combined.cpp*/#include <iostream.h>class a{int i;public:a (int i) {i = i;} ~a () {}void f () Const{}};class b{int i;public:b (int i) {i = i;} ~b () {}void F () const {}};class c:public B{a a;//c inherits B and has a member object (this is an object of Class A) public:c (int I): B (i), a (i) {}//constructor is called in the initialization expression table Base class constructors and member object constructors. ~c () {}void f () const//function C::f () redefined the B::F () it inherits, and also calls the base class version, which also calls A.F () {A.F (); B::f ();}}; int main () {c C (47);} </strong></span>

6.

<span style= "FONT-SIZE:18PX;" As ><strong>/*order.cpp*//* can see, constructs begin at the root of the class hierarchy, and at each level, the base class constructor is called first, and then the member object constructor is called. Calling destructors is strictly in the opposite order of constructors-this is important because potential dependencies are considered. */#include <fstream.h>ofstream out ("Order.out"), #define Class (ID) class Id{public:  ID (int) {out << #ID "constructor\n";}  ~id () {out << #ID "destructor\n";}}; CLASS (BASE1); CLASS (Member1); CLASS (MEMBER2); CLASS (MEMBER3); Class (MEMBER4), class Derived1:public base1{member1 m1;member2 m2;public:derived1 (int): M2 (1), M1 (2), BASE1 (3) {Out < < "derived1 constructor\n";} ~derived1 () {out << "derived1 destructor\n";}}; Class Derived2:public Derived1{member3 m3;member4 m4;public:derived2 (): M3 (1), derived1 (2), M4 (3) {out << derived 2 constructor\n ";} ~derived2 () {out << "Derived2 destructor\n";}}; int main () {derived2 D2;return 0;} </strong></span>

7.

<span style= "FONT-SIZE:18PX;" ><strong>/* name hiding if you have a function name overloaded several times in a base class, redefining it in a derived class obscures all base class versions, which means that they become unusable in derived classes. *//*hide.cpp*//* because Bart redefined d o H (), none of these base-class versions are callable for Bart objects. At this point, the compiler attempts to transform the parameter into a Milhouse object and reports an error because it cannot find such a transformation. */#include <iostream.h>class homer{public:int doh (int) Const{return 1;} Char doh (char) Const{return ' d ';} float doh (float) Const{return 1.0;}}; Class Bart:public Homer{public:class milhouse{};void doh (Milhouse) const {}};int main () {Bart B;    !b.doh (1);//!b.doh (' x ');//!b.doh (1.0);} </strong></span>

8.

<span style= "FONT-SIZE:18PX;" ><strong>/* is created by the compiler instead of the inherited function *//*ninherit.cpp*/#include <fstream.h>ofstream out ("Ninherit.out"); class Root{public:root () {out << "root () \ n";} Root (root&) {out << "root (root&) \ n";} root (int) {out << "root (int) \ n";} root& operator= (const root&) {out << "root::operator= () \ n"; return *this;} Class Other{};operator Other () Const//operator other () completes the automatic type transformation, from the root object to the embedded class other object {out << "Root::operator oth ER () \ n "; return other ();} ~root () {out << "~root () \ n";}}; Class Derived:public Root {};//class derived is inherited directly from root and does not create a function (see how the compiler Reacts)//in Derived, operator= () is also synthesized as a new function, using member functions to assign values, because this The function does not explicitly write out void F (root::other) {}//function f () in the new class to take an other object to test this automatic type transformation function int main () {derived d1;derived D2 = d1;//!derived D3 (1) ;d 1 = d2;f (d1); return 0;} </strong></span>

9.

<span style= "FONT-SIZE:18PX;" The ><strong>/* combination is typically used when you want the new class to have existing class performance, and you do not want the class to exist as its interface. This means embedding an object that is intended to implement the performance of the new class, while the user of the new class sees the newly defined interface rather than the interface from the old class. To do this, embed the private object of the existing class inside the new class. Sometimes it makes sense to allow class users to access the combination of the new class directly, which makes the member object public. member functions hide their own implementations, so when the user knows that we are assembling a set of parts and makes the interface easier for them to understand, it will be safe to *//*car.cpp*///a little thought to see that it is meaningless to combine a car with a vehicle object-a car cannot contain a vehicle, it itself/ /is a vehicle. This is-a relationship is expressed by inheritance, while the has-a relationship is expressed in combination. #include <iostream.h>class engine{public:void Start () const {}void rev () const {}void Stop () const {}};class wheel{p Ublic:void Inflate (int psi) Const {}};class window{public:void Rollup () const {}void rolldown () const {}};class Door{publ Ic:window window;void Open () const {}void close () const {}};class car{public:engine engine;wheel wheel[4];d Oor left, right ;}; int main () {car car; Car.left.Window.rollup (); Car.wheel[0].inflate (a); return 0;} </strong></span>

.

<span style= "FONT-SIZE:18PX;" ><strong>/* subtype Settings *//*fname1.cpp*/#include <fstream.h> #include <strstrea.h> #include "e:\vc++\7 _31_2\allege.h "Class Fname1{ifstream file;enum{bsize =};char buf[bsize];ostrstream name;int nameset;public:fname1 (): Name (buf, bsize), NameSet (0) {}fname1 (const char* filename): file (filename), name (BUF, bsize) {allegefile (File); Name << filename << ends;nameset = 1;} Const char* name () Const{return buf;} void name (const char* newname) {if (nameset) {return;} Name << newname << ends;nameset = 1;} Operator ifstream& () {return File;}}; int main () {fname1 file ("Fname1.cpp"); cout << file.name () << endl;//error:rdbuf () not a Member//!cout < < File.rdbuf () << endl;//because an automatic type conversion occurs only in a function call, not during a member selection, return 0;} </strong></span>

one by one.

<span style= "FONT-SIZE:18PX;" ><strong>/* subtype Settings *//*fname2.cpp*/#include <fstream.h> #include <strstrea.h> #include "e:\vc++\7 _31_2\allege.h "Class fname2:public ifstream{enum{bsize =};char buf[bsize];ostrstream name;int Nameset;public:fnam E2 (): Name (buf, bsize), NameSet (0) {}fname2 (const char* filename): ifstream (filename), name (BUF, bsize) {name << fi Lename << ends;nameset = 1;} Const char* name () Const{return buf;} void name (const char* newname) {if (nameset) {return;} Name << newname << ends;nameset = 1;}}; int main () {fname2 file ("Fname2.cpp"); allegefile (file); cout << "Name:" << file.name () << Endl;const Bsize = 100;char buf[bsize];file.getline (buf, bsize); FILE.SEEKG ( -200, ios::end); cout << file.rdbuf () << Endl;return 0;} </strong></span>

.

<span style= "FONT-SIZE:18PX;" ><strong>/* inheritance is to take an existing class and make a specialized version of it *//*inhstak.cpp*/#include "e:\vc++\8_4_3\stackl1.h" #include "E:\VC ++\8_4_1\strings.h "#include <fstream.h> #include" e:\vc++\7_31_2\allege.h "class Stringlist:public stack{ Public:void push (string* str) {stack::p ush (str);} string* Peek () Const{return (string*) stack::p eek ();} string* pop () {return (string*) stack::p op ();}}; int main () {Ifstream file ("Text.cpp"); allegefile (file); Const BUFSIZE = 100;char Buf[bufsize]; Stringlist Textlines;while (File.getline (buf, bufsize)) {Textlines.push (String::make (BUF));} String* S;while ((s = Textlines.pop ())! = 0) {cout << *s << Endl;} return 0;} </strong></span>

.

<span style= "FONT-SIZE:18PX;" ><strong>/* to private inherited members when private inheritance is made, all public members of the base class become private. If you want any of them to be visible, simply declare their names with the public option of the derived class. *//*priving.cpp*/#include <iostream.h>class base1{public:char f () Const{return ' a ';} int g () Const{return 2;} Float h () Const{return 3.0;}}; Class Derived:base1{public:base1::f;base1::h;}; int main () {derived D;D.F ();d. h ();//!d.g (); return 0;} </strong></span>

.

<span style= "FONT-SIZE:18PX;" ><strong>/* data members are best private because we should reserve the right to change the internal implementation. Then we can control access to the inheritors of the class through the Protect member function. When *//*protect.cpp*//* inherited inheritance is protected, the base class defaults to private, which means that all public member functions are private to the user of the new class. Usually we will let inherit public, so that the interface of the base class is also the interface of the derived class. However, the protected keyword can also be used during inheritance. A protected derivation means "This implementation" to other classes, but to derived classes and friends is "is-a". It is not commonly used, it exists only for the integrity of the language. */#include <fstream.h>class base{int i;protected:int read () Const{return I;} void set (int i) {i = i;} public:base (int I = 0): I (i) {}int value (int m) const{return m * I;}}; Class Derived:public Base{int j;public:derived (int j = 0): J (j) {}void change (int x) {set (x);}}; int main () {return 0;} </strong></span>

A.

<span style= "FONT-SIZE:18PX;" ><strong>/* upward mapping *//*wind.cpp*//* in tune (), which is valid for instrument and any type derived from instrument, which will wind's object, An activity that converts a reference or pointer to a instrument object, reference, or pointer is called an upward mapping.  */#include <iostream.h>enum Note {middlec, Csharp, Cflat};class instrument{public:void Play (note) const {}};class Wind:public Instrument {};void tune (instrument& i) {i.play (Middlec);} int main () {Wind flute;tune (flute);//wind w;//instrument* IP = &w;//instrument& ir = w;// The compiler can only handle IP as a instrument pointer. This means that it does not know that the IP actually points to wind's object.    //So, when calling the play () member function, if    //ip->play (Middlec) is used;    The compiler only knows that it is calling play () for a instrument pointer, and calls the basic version of Instrument∷play (),    //instead of calling Wind∷play () that it should do. This will result in incorrect results. return 0;} </strong></span>

.

<span style= "FONT-SIZE:18PX;" The ><strong>/*stringlist object is used only as a string containment and does not need to be mapped upward, so a more appropriate approach might be to combine *//*inhstak2.cpp*/#include "e:\vc++\8_4_3\ Stackl1.h "#include" e:\vc++\8_4_1\strings.h "#include <fstream.h> #include" e:\vc++\7_31_2\allege.h "class Stringlist{stack stack;public:void push (string* str) {stack.push (str);} string* Peek () Const{return (string*) Stack.peek ();} string* pop () {return (string*) Stack.pop ();}}; int main () {Ifstream file ("Text.cpp"); allegefile (file); Const BUFSIZE = 100;char Buf[bufsize]; Stringlist Textlines;while (File.getline (buf, bufsize)) {Textlines.push (String::make (BUF));} String* S;while ((s = Textlines.pop ())! = 0) {cout << *s << Endl;} return 0;} </strong></span>



Three. Exercises + answers

1. Modify the CAR.CPP so that it also inherits from the class called vehicle, placing the appropriate member function in vehicle (that is, supplementing some member functions). Add a non-default constructor to vehicle, which must be called inside the constructor of car.

#include <iostream.h>class engine{public:void Start () const {}void rev () const {}void Stop () const {}};class wheel{p Ublic:void Inflate (int psi) Const {}};class window{public:void Rollup () const {}void rolldown () const {}};class Door{publ Ic:window window;void Open () const {}void close () const {}};class vehicle{public:vehicle () {}void g () {}void f () {}};class C Ar:vehicle{public:engine Engine;wheel wheel[4];d Oor left, Right;car () {vehicle ();}}; int main () {car car; Car.left.Window.rollup (); Car.wheel[0].inflate (a); return 0;}


2. Create two classes, A and B, with default constructors that can announce themselves. Inherits a new class from a, called C, and creates a member object of B in C without creating a constructor for C. Create an object of Class C and observe the results.

#include <iostream.h>class a{int i;public:a (int i = 0) {i = I;cout << "a::a (int i)" << Endl;}; Class B{int j;public:b (int j = 0) {j = j;cout << "b::b (int j)" << Endl;}; Class C:public a{public:b B;}; int main () {C C;return 0;

Call Result:


3. Use inheritance, specialization in 1th 2 (Pstash. H & Pstash. CPP), which allows it to accept and return a string pin. Pstash class. Modify the Pstest. CPP and test it. Changing this class makes Pstash a member object.

/*pstash.h*/#include "e:\vc++\8_4_1\strings.h" #ifndef pstash_h_#define pstash_h_class pstash{int quantity;int next; void** storage;//storage is a void pointer array void inflate (int increase);p Ublic:pstash () {quantity = 0;storage = 0;next = 0;} ~pstash () {delete storage;} int Add (void* element), void* operator[] (int index) const;int count () Const{return next;}; Class Stringlist:public Pstash{public:int Add (string* Element) {return Pstash::add (element);} string* operator[] (int index) Const{return (string*) pstash::operator[] (index);} int count () Const{return pstash::count ();}}; #endif

/*pstash.cpp*/#include "pstash.h" #include <iostream.h> #include <string.h>int pstash::add (void* Element) {Const INFLATESIZE = 10;if (next >= quantity) {inflate (inflatesize);}  Storage[next+1] = Element;return (next-1);//index number}void* pstash::operator[] (int index) const{if (index >= Next | | Index < 0) {return 0;} return Storage[index];} void pstash::inflate (int increase) {Const PSZ = sizeof (void*); void** st = new Void*[quantity + increase];memset (St, 0, (qua Ntity + Increase) * Psz) memcpy (St, storage, quantity * psz); quantity + = Increase;delete storage;storage = st;}

/*pstest.cpp*/#include "pstash.h" #include <fstream.h> #include "e:\vc++\7_31_2\allege.h" int main () {Ifstream File ("Pstest.cpp"); allegefile (file); Const BUFSIZE = 80;char Buf[bufsize]; Stringlist Textlines;while (File.getline (buf, bufsize)) {Textlines.add (String::make (BUF));} return 0;}


4. Use private and protected inheritance to create two new classes from a base class. Then try to map the object of the derived class upward to become the base class. Explain what happened.

#include <iostream.h>enum Note {middlec, Csharp, Cflat};class a{public:void Play (note) const {}};class b:private A {};class c:protected a {};void tune (a& i) {i.play (Middlec);} int main () {b flute1;//!tune (flute1);//error C2243: ' Type cast ': Conversion from ' class B * ' to ' class A & ' exists, BU T is Inaccessiblec Flute2;//!tune (flute2),//error C2243: ' Type cast ': Conversion from ' class C * ' to ' class A & ' Exis TS, but is inaccessiblereturn 0;}


The above code is only for reference, if there are errors please point out, thank you ~

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

"C + + Programming thought" chapter 13th inheritance and combination (original code + exercise + solution)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.