Inheritance is a relationship between two classes such that one class takes on (inherits) the properties and behaviors (data and function members) of another class. The derived class inherits from a base class. This process facilitates code reuse and is a formal method of identifying natural relationships between classes.
A derived class may be the base for another class. Several classes may inherit from one class, and a derived class may inherit from several classes. Just like people! This is called multiple inheritance.
The following example illustrates some of the basic inheritance concepts.
Example 7-1 - First inheritance example
1 // File: ex7-1.cpp
2
3 #include <iostream>
4 using namespace std;
5
6 class Base
7 {
8 protected:
9 int b;
10 public:
11 Base(int n);
12 void print(void) const { cout << "Base data is " << b << endl; }
13 };
14
15 Base::Base(int n)
16 {
17 cout << "created Base object: " << this << endl;
18 b = n;
19 }
20
21 class Derived : public Base
22 {
23 private:
24 int d;
25 public:
26 Derived(int x,int y);
27 void print(void) const;
28 void printBase(void)
29 { cout << this << "'s Base is " << b << endl; }
30 };
31
32 Derived::Derived(int x, int y) : Base(x)
33 {
34 cout << "created Derived object: " << this << endl;
35 d = y;
36 }
37
38 void Derived::print(void) const
39 {
40 cout << "Derived data is " << d << endl;
41 Base::print();
42 }
43
44 int main(void)
45 {
46 Base b1(5);
47
48 // print base object
49 b1.print();
50 cout << endl;
51 Derived d1(3,4);
52
53 // print derived object
54 d1.print();
55 cout << endl;
56
57 d1.printBase();
58
59 // call base class print() from derived class object
60 d1.Base::print();
61 cout << endl;
62
63 cout << "how big is an int? " << sizeof(int) << endl;
64 cout << "how big is a Base? " << sizeof b1 << endl;
65 cout << "how big is a Derived? " << sizeof d1 << endl;
66 return 0;
67 }****** Output ******
created Base object: 001EFC1C
Base data is 5
created Base object: 001EFC0C
created Derived object: 001EFC0C
Derived data is 4
Base data is 3
001EFC0C's Base is 3
Base data is 3
how big is an int? 4
how big is a Base? 4
how big is a Derived? 8
Inheritance Notes
- The base class data members are usually protected. Thus, they may be accessible in the derived class.
- Public inheritance is the most common type. In public inheritance, the protected base members are accessible and are also protected in the derived class. And also, the public base members remain public in the derived class. Private base members are not accessible in any type of inheritance. Access in derived classes to the base members by inheritance type is summarized in the following table:

- The derived class constructors automatically makes a call to the base class constructor. You can cause a certain base class constructor to be called by using constructor initialization list syntax. If you don't, then the default base class constructor is called (and it had better be there).
The base class constructor executes before the derived class constructor, and the derived destructor will execute before the base destructor. - The derived class will use the accessible member functions of the base class unless it has a function of the same signature.
- The following members are not inherited by the derived class:
- constructors
- destructors
- friend functions
- Static data members may be inherited and hence, are shared among the base and derived class objects, providing they have public or protected access. Further, static member functions may also be inherited.
Derived classes are also called subclasses, base classes are also called superclasses.
The following example illustrates a typical inheritance situation. Suppose you have a number class in which addition with a plus sign is defined. This class works well, but you would also like to be able to use it for subtraction. To do so, define your "own" class and inherit the number class. Add a subtraction function to your class.
Example 7-2 - Another easy inheritance example.
1 // File: ex7-2.cpp – Adding functionality to a class using inheritance
2
3 #include <iostream>
4 using namespace std;
5
6 class Number
7 {
8 protected:
9 int x;
10 public:
11 Number() {}
12 Number(int n) { x = n; }
13 Number(const Number& n) { x = n.x; }
14 void print(void) const { cout << x << endl; }
15 Number& operator=(const Number& z) { x = z.x; return *this; }
16 Number operator+(const Number& y) const { return x + y.x; }
17 };
18
19 class MyNumber : public Number
20 {
21 public:
22 MyNumber() {}
23 MyNumber(int n) : Number(n) { }
24 MyNumber(const Number& n) : Number(n) {}
25 MyNumber(const MyNumber& m) : Number(m) {}
26 MyNumber operator-(const MyNumber& y) const { return x - y.x; }
27 };
28
29 int main(void)
30 {
31 Number n1(4), n2(5);
32 Number n3;
33 cout << "n1="; n1.print();
34 cout << "n2="; n2.print();
35 n3 = n1 + n2;
36 cout << "n3="; n3.print();
37 cout << endl;
38
39 MyNumber mn1(7), mn2(4);
40 MyNumber mn3;
41 cout << "mn1="; mn1.print();
42 cout << "mn2="; mn2.print();
43 mn3 = mn1 + mn2;
44 cout << "mn3="; mn3.print();
45 mn3 = mn1 - mn2;
46 cout << "mn3="; mn3.print();
47
48 MyNumber mn4(n1);
49 cout << "mn4="; mn4.print();
50
51 MyNumber mn5(mn1);
52 cout << "mn5="; mn5.print();
53
54 return 0;
55 }****** Output ******
n1=4
n2=5
n3=9
mn1=7
mn2=4
mn3=11
mn3=3
mn4=4
mn5=7
- What is the purpose of the default constructors in both classes?
- How can the MyNumber copy constructor pass a MyNumber& to the Number copy constructor?
- What is returned from the operator+ and operator- functions?
1 // File: ex7-3.cpp – Inherit the deck class
2
3 #include <iostream>
4 #include <stdlib>
5 using namespace std;
6
7 char* value_name[13] =
8 {"two","three","four","five","six","seven","eight",
9 "nine","ten","jack","queen","king","ace"};
10
11 char* suit_name[4] = {"clubs","diamonds","hearts","spades"};
12
13 class card
14 {
15 private:
16 int value;
17 int suit;
18 public:
19 card(void) {}
20 card(int n) { value = n % 13; suit = n / 13; }
21 card(int p, int s) { value = p; suit = s; }
22 void print(void) const {
23 cout <<value_name[value]<<" of "<<suit_name[suit]<<endl;
24 }
25 };
26
27 class deck
28 {
29 protected:
30 card* d;
31 const int num_cards;
32 public:
33 deck(int);
34 ~deck();
35 void shuffle(void);
36 void print(void) const;
37 };
38
39 deck::deck(int n) : num_cards(n) // Is this syntax required?
40 {
41 d = new card[n];
42 }
43
44 deck::~deck() {
45 delete [] d;
46 }
47
48 void deck::print(void) const {
49 for (int i = 0; i < num_cards; i++) d[i].print(); return;
50 }
51 void deck::shuffle(void)
52 {
53 cout << "I am shuffling the deck\n";
54 card temp;
55 for (int i = 0; i < num_cards; i++)
56 {
57 int k = rand() % num_cards;
58 temp = d[i];
59 d[i] = d[k];
60 d[k] = temp;
61 }
62 return;
63 }
64
65 class poker_deck : public deck
66 {
67 public:
68 poker_deck(void);
69 };
70
71 poker_deck::poker_deck(void) : deck(52)
72 {
73 for (int i = 0; i < num_cards; i++) d[i] = card(i);
74 }
75
76 class pinocle_deck : public deck
77 {
78 public:
79 pinocle_deck(void);
80 };
81
82 pinocle_deck::pinocle_deck(void) : deck(48)
83 {
84 for (int i = 0; i < 48; i++) d[i] = card(i%6+7,i/2%4);
85 }
86
87
88 int main(void)
89 {
90 poker_deck pd;
91 pd.print();
92 cout << endl;
93 pinocle_deck pin;
94 pin.print();
95 pin.shuffle();
96 pd.shuffle();
97 return 0;
98 }****** Output ******
two of clubs <= the poker deck starts here
three of clubs
four of clubs
five of clubs
six of clubs
seven of clubs
eight of clubs
..
..
..
queen of spades
king of spades
ace of spades
nine of clubs <= the pinocle deck starts here
ten of clubs
jack of diamonds
queen of diamonds
king of hearts
ace of hearts
nine of spades
ten of spades
jack of clubs
queen of clubs
king of diamonds
ace of diamonds
nine of hearts
ten of hearts
..
..
..
ace of diamonds
nine of hearts
ten of hearts
jack of spades
queen of spades
king of clubs
ace of clubs
nine of diamonds
ten of diamonds
jack of hearts
queen of hearts
king of spades
ace of spades
…
Example 7-4 - Account classes
1 // File: ex7-4.cpp – Derive Savings and Checking from Account
2
3 #include <iostream>
4 using namespace std;
5
6 class Account
7 {
8 protected:
9 long acct_no;
10 double balance;
11 double int_rate; // annual interest rate
12 public:
13 Account(long acc_no,double init_bal,double i_rate);
14 void deposit(double amount);
15 void withdraw(double amount);
16 void month_end(void);
17 void display(void) const;
18 };
19
20 Account::Account(long acc_no,double init_bal,double i_rate)
21 {
22 cout << "* New Account\t";
23 acct_no = acc_no;
24 balance = init_bal;
25 int_rate = i_rate;
26 display();
27 }
28
29 void Account::deposit(double amount)
30 {
31 cout << "Account: " << acct_no << " deposit = "<<amount <<endl;
32 balance += amount;
33 }
34
35 void Account::withdraw(double amount)
36 {
37 cout << "Account: " << acct_no <<" withdraw = "<<amount <<endl;
38 balance -= amount;
39 }
40
41 void Account::display(void) const
42 {
43 cout << "Account: " << acct_no << " balance = " << balance
44 << endl << endl;
45 }
46
47 void Account::month_end(void)
48 {
49 cout << "Account month-end processing: " << acct_no << endl;
50 balance *= (1.+int_rate/12.);
51 display();
52 }
53
54
55 class SavingsAccount : public Account
56 {
57 public:
58 SavingsAccount(long a_no, double i_b = 50., double i_r = .05)
59 :Account(a_no,i_b,i_r) { }
60 };
61
62
63 class CheckingAccount : public Account
64 {
65 private:
66 double min_balance;
67 double service_charge;
68 public:
69 CheckingAccount(long,double,double=300.,double= 2.,double =.04);
70 void process_check(double amt) { withdraw(amt); }
71 void month_end(void);
72 };
73
74 CheckingAccount::CheckingAccount(long acc_no, double init_bal,
75 double min_bal,double service_chg,
76 double i_rate)
77 : Account(acc_no,init_bal,i_rate)
78 {
79 min_balance = min_bal;
80 service_charge = service_chg;
81 }
82
83 void CheckingAccount::month_end(void)
84 {
85 cout <<"checking Account month-end processing:"<<acct_no<<endl;
86 balance *= (1.+int_rate/12.);
87 if (balance < min_balance) balance -= service_charge;
88 display();
89 }
90 int main(void)
91 {
92 SavingsAccount Mysavings(1234560L,500.);
93 CheckingAccount Mychecking(1234561L,1000.);
94
95 Mysavings.deposit(100.);
96 Mysavings.display();
97
98 Mysavings.withdraw(200.);
99 Mysavings.display();
100
101 Mychecking.deposit(100.);
102 Mychecking.display();
103
104 Mychecking.process_check(200.);
105 Mychecking.display();
106
107 Mysavings.month_end();
108
109 Mychecking.month_end();
110 return 0;
111 }****** Output ******
* New account account: 1234560 balance = 500
* New account account: 1234561 balance = 1000
account: 1234560 deposit = 100
account: 1234560 balance = 600
account: 1234560 withdraw = 200
account: 1234560 balance = 400
account: 1234561 deposit = 100
account: 1234561 balance = 1100
account: 1234561 withdraw = 200
account: 1234561 balance = 900
account month-end processing: 1234560
account: 1234560 balance = 401.666656
checking account month-end processing: 1234561
account: 1234561 balance = 903
Example 7-5 - Triangle classes
This example demonstates two levels of inheritance.
1 // File: ex7-5.cpp – triangle classes
2
3 #include <iostream>
4 #include <cmath>
5 using namespace std;
6
7 class triangle {
8 protected:
9 double a,b,c;
10 public:
11 triangle(double s1,double s2,double s3) : a(s1),b(s2),c(s3){}
12 void show() const {
13 cout << "triangle " << this << " sides "
14 << a << ' ' << b << ' ' << c << endl;
15 }
16 void area(void) const;
17 };
18
19 void triangle::area(void) const {
20 double s = (a + b + c)/2.0; // s = semiperimeter
21 cout << " area of " << this << " = "
22 << (sqrt(s*(s-a)*(s-b)*(s-c))) << endl << endl;
23 return;
24 }
25
26 class isosceles : public triangle {
27 public:
28 isosceles(double base,double leg) : triangle(base,leg,leg) {}
29 };
30
31 class equilateral : public isosceles {
32 public:
33 equilateral(double side) : isosceles(side,side) {}
34 };
35
36 int main(void) {
37 triangle t1(3,4,5);
38 t1.show();
39 t1.area();
40
41 isosceles t2(2,4);
42 t2.show();
43 t2.area();
44
45 equilateral t3(5);
46 t3.show();
47 t3.area();
48 return 0;
49 }****** Output ******
triangle 0012FF74 sides 3 4 5
area of 0012FF74 = 6
triangle 0012FF5C sides 2 4 4
area of 0012FF5C = 3.87298
triangle 0012FF44 sides 5 5 5
area of 0012FF44 = 10.8253
Private Inheritance
- Private inheritance may be used to represent a "has-a" relationship between two classes. (Fortunately) this type of inheritance is not all that common. Private inheritance is more commonly replaced by containment, or a container relationship. Instead of a "has-a" relationship between classes, private inheritance is more commonly used to express an "in terms of" relationship. Here are some notes regarding private inheritance:
- Private inheritance is the default inheritance type, even though public inheritance is by far the more common type of inheritance. This is what you get if you leave off the "public" after the colon in the class definition.
- Private inheritance is used to indicate that one class "contains" another class, but the containment is limited to exactly one instance of the base class.
- The (privately) derived class inherits the base class public and protected members, but does not "pass them on". That is, the derived class must provide it's own public interface to any base class members desired.
- Private inheritance is used when you want to make use of the base class, but you wish to hide the base class public interface or you wish to provide your own public interface.
The following example demonstrates private inheritance. The objective is to create a name class that is defined in terms of the "standard" string class. To keep the class simple, the name class has a simple user interface, thus hiding the complexity of the string class.
1 // Example 7-6 - private inheritance
2
3 #include <iostream>
4 #include <string>
5 using namespace std;
6
7 class name : private string
8 {
9 public:
10 name(const char *);
11 void print() const;
12 string first_last() const;
13 string initials() const;
14 void change_last(const string& new_last);
15 };
16
17 name::name(const char* n) : string(n) {}
18
19 void name::print() const {
20 cout << c_str() << ".\n";
21 }
22
23 string name::first_last() const {
24 size_t comma_pos = find(',');
25 size_t second_space = find_last_of(' ');
26 return substr(comma_pos+2,second_space-comma_pos-2) +
27 ' ' + substr(0,comma_pos);
28 }
29
30 string name::initials() const {
31 string inits;
32 inits = data()[find(',')+2];
33 return inits + data()[length()-1] + *data();
34 }
35
36 void name::change_last(const string& new_last) {
37 replace(0,find(','),new_last);
38 }
39
40 int main() {
41 name joe("Bentley, Joseph E");
42 joe.print();
43 cout << joe.first_last() << endl;
44 cout << joe.initials() << endl;
45 joe.change_last("Smith");
46 joe.print();
47 return 0;
48 }****** Output ******
Bentley, Joseph E.
Joseph Bentley
JEB
Smith, Joseph E.
Multiple Inheritance
Example 7-7 - First Multiple Inheritance Example
1 File: ex7-7.cpp – multiple inheritance
2
3 #include <iostream>
4 using namespace std;
5
6 class one {
7 protected:
8 int a,b;
9 public:
10 one(int z,int y) { a = z; b = y; }
11 void show(void) const { cout << a << ' ' << b << endl; }
12 };
13
14 class two {
15 protected:
16 int c,d;
17 public:
18 two(int z,int y) { c = z; d = y; }
19 void show(void) const { cout << c << ' ' << d << endl; }
20 };
21
22 class three : public one, public two
23 {
24 private:
25 int e;
26 public:
27 three(int,int,int,int,int);
28 void show(void) const
29 { cout <<a<< ' ' <<b<< ' ' <<c<< ' ' <<d<< ' ' <<e<< endl;}
30 };
31
32 three::three(int a1, int a2, int a3, int a4, int a5)
33 : one(a1,a2),two(a3,a4)
34 {
35 e = a5;
36 }
37
38 int main(void)
39 {
40 one abc(5,7);
41 abc.show(); // prints 5 7
42 two def(8,9);
43 def.show(); // prints 8 9
44 three ghi(2,4,6,8,10);
45 ghi.show(); // prints 2 4 6 8 10
46 return 0;
47 }The next example illustrates a more complicated inheritance situation. It models the relationship between types of quadrilaterals. This relationship is shown in the following figure:
Note that the parallelogram class will be derived from the quadrilateral class, both the rhombus and rectangle classes will be derived from the parallelogram class. And the square is derived from both the rhombus and the rectangle classes. It's the square class that makes this multiple inheritance.
Example 7-8 - Quadrilaterals
1 // File: ex7-8.cpp
2
3 #include <iostream>
4 #include <cmath>
5 using namespace std;
6
7 class quadrilateral
8 {
9 protected:
10 double a,b,c,d;
11 public:
12 quadrilateral(double s1,double s2,double s3,double s4)
13 : a(s1), b(s2), c(s3), d(s4) {}
14 quadrilateral() {}
15 void show() const
16 {
17 cout << "quadrilateral: " << this << " sides "
18 << a << ' ' << b << ' ' << c << ' ' << d << endl;
19 }
20 };
21 class trapezoid : public quadrilateral
22 {
23 public:
24 trapezoid(double base1,double base2,double leg1,double leg2)
25 : quadrilateral(base1,leg1,base2,leg2) {}
26 };
27
28 class isosceles_trapezoid : public trapezoid
29 {
30 public:
31 isosceles_trapezoid(double base1,double base2,double leg)
32 : trapezoid(base1,leg,base2,leg) {}
33 };
34
35 class parallelogram : public quadrilateral
36 {
37 protected:
38 int angle;
39 public:
40 parallelogram(double s1,double s2, int ang)
41 : quadrilateral(s1,s2,s1,s2) { angle = ang; }
42 parallelogram() { }
43 void show_angles(void) const
44 {
45 cout << "angles = " << angle << ' ' << (180-angle) << endl;
46 }
47 };
48
49 class rectangle : virtual public parallelogram
50 {
51 public:
52 rectangle(double base, double height)
53 : parallelogram(base,height,90) {}
54 rectangle() {}
55 };
56
57 class rhombus: virtual public parallelogram
58 {
59 public:
60 rhombus(double side,int ang) : parallelogram(side,side,ang){}
61 rhombus() {}
62 };
63
64 class square : public rhombus,public rectangle
65 {
66 public:
67 square(double side) : parallelogram(side,side,90) {}
68 };
69 int main(void)
70 {
71 quadrilateral q1(1,2,3,4);
72 q1.show();
73
74 trapezoid q2(22,13,8,15);
75 q2.show();
76
77 isosceles_trapezoid q3(18,8,13);
78 q3.show();
79
80 parallelogram q4(4,3,45);
81 q4.show();
82 q4.show_angles();
83
84 rectangle q5(4,3);
85 q5.show();
86 q5.show_angles();
87
88 rhombus q6(5,45);
89 q6.show();
90 q6.show_angles();
91 cout << endl;
92
93 square q7(5);
94 q7.show();
95 q7.show_angles();
96
97 return 0;
98 }****** Output ******
quadrilateral: 0x3dc9ffd6 sides 1 2 3 4
quadrilateral: 0x3dc9ffb6 sides 22 8 13 15
quadrilateral: 0x3dc9ff96 sides 18 8 13 13
quadrilateral: 0x3dc9ff74 sides 4 3 4 3
angles = 45 135
quadrilateral: 0x3dc9ff52 sides 4 3 4 3
angles = 90 90
quadrilateral: 0x3dc9ff2e sides 5 5 5 5
angles = 45 135
quadrilateral: 0x3dc9ff0a sides 5 5 5 5
angles = 90 90
Note: The rectangle and rhombus classes both inherit the parallelogram class. Their inheritance is designated virtual, so that if a class is derived from both of the them, the parallelogram data will not be repeated in the class.

沒有留言:
張貼留言