⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 09章 继承.txt

📁 C++大学教程txt版中文版 C++大学教程txt版中文版
💻 TXT
📖 第 1 页 / 共 5 页
字号:
80         << "\nRadius is " << cy1.getRadius()
81         << "\nHeight is " << cy1.getHeight() << "\n\n";
82
83 // use set functions to change the Cylinder's attributes
84    cy1.setHeight(10);
85    cy1.setRadius(4.25);
86    cy1.setPoint(2,2);
87    cout << "The new location, radius, and height of cy1 are:\n"
88         << cy1 << '\n';
89
90    // display the Cylinder as a Point
91    Point &pRef = cy1;    // pRef "thinks" it is a Point
92    cout << "\nCylinder printed as a Point is: "
93         << pRef << "\n\n";
94
95    // display the Cylinder as a Circle
96    Circle &circleRef = cy1;    // circleef thinks it is a Circle
97    cout << "Cylinder printed as a Circle is:\n" << circleRef
98         << "\nArea: "<< circleRef.area() << endl;
99
100   return 0;
101 }

输出结果:
X coordinate is 12
Y coordinate is 23
Radius is 2.5
Height is 5.7

The new location, radius, and height of cy1 are:
Center = [ 2, 2 ]; Radius = 4.25; Height = 10.00

Cylinder printed as a Point is: [ 2, 2 ]

Cylinder printed as a Circle is:
Center = [2, 2] ; Radius = 4.25
Area: 56.74

                                   图 9.10 演示 Cylinder 类

9.15  多重继承
    本章前面讨论了单一继承,即一个类是从一个基类派生来的。一个类也可以从多个基类派生而来,这种派生称为“多重继承”(multiPle inheritance)。多重继承意味着一个派生类可以继承多个基类的成员,这种强大的功能支持了软件的复用性,但可能会引起大量的歧义性问题。

    编程技巧9.1
    多重继承使用得好可具有强大的功能。当新类型与两个或多个现有类型之间存在”是”关系时(即类型A“是”类型B并且也“是”类型c)应该使用多重继承。

    图9.11中的程序是一个多重继承的例子。类Base1包含一个protected数据成员int value,还包含设置value值的构造函数和返回value值的public成员函数getData。
    类Base2和类Base1相似,只不过它的protected数据成员是char letter。类Base2也包含一个Public成员函数getData,但是该函数返回的是char letter的值。
    类Derivcd通过多重继承机制继承了类Base1和类Base2,它有一个private数据成员float real和一个读取float real的public成员函数getReal。
    多重继承是非常直接的,即在class derived后的冒号(:)之后跟上用逗号分开的公有基类列表。还可以看到,构造函数Derived显式地调用了每个基类(即Bae1和Base2)的构造函数。同样,按指定的继承顺序调用基类构造函数,而不是按构造函数出现的顺序调用。如果成员初始化值列表中不显式调用基类构造函数,则隐式调用基类的默认构造函数。

1 // Fig. 9.11: basel.h
2 // Definition of class Basel
3 #ifndef BASE1_H
4 #define BASE1_H
5
6 class Base1 {
7 public:
8   Base1( int x ) { value = x; }
9   int getData() const { return value; }
10 protected:     // accessible to derived classes
11   int value;  // inherited by derived class
12 };
13
14 #endif
15 // Fig. 9.11: base2.h
16 // Definition of class Base2
17 #ifndef BASE2_H
18 #define BASE2_H
19
20 class Base2 {
21 public:
22   Base2( char c ) { letter = c; }
23   char getData() const { return letter; }
24 protected:      // accessible to derived classes
25   char letter;  // inherited by derived class
26 };
27
28 #endif
29 // Fig. 9.11: derived.h
30 // Definition of class Derived which inherits
31 // multiple base classes (Basel and Base2).
32 #ifndef DERIVED_H
33 #define DERIVED_H
34
35 #include "base1.h"
36 #include "base2.h"
37
38 // multiple inheritance
39 class Derived : public Base1, public Base2 {
40   friend ostream &operator<<( ostream &, const Derived & );
41
42 public:
43   Derived( int, char, double };
44   double getReal() const;
45
46 private:
47   double real;  // derived class's private data
48 };
49
50 #endif
51 // Fig. 9.11: derived.cpp
52 // Member function definitions for class Derived
53 #include <iostream.h>
54 #include "derived.h"
55
56 // Constructor for Derived calls constructors for
57 // class Basel and class Base2.
58 // Use member initializers to call base-class constructors
59 Derived::Derived( int i, char C, double f )
60   : Base1( i ), Base2( c ), real ( f ) {
61
62 // Return the value of real
63 double Derlved::getRealO const { return real; }
64
65 // Display all the data members of Derived
66 ostream &operator<<( ostream &output, const Derived &d )
67 {
68   output <<"   Integer: "<< d.value
69          << "\n Character: "<< d.letter
70          << "\nReal number: "<< d.real;
71
72   return output;  // enables cascaded calls
73 }
74 / Fig. 9.11: fig09_ll.cpp
75 // Driver for multiple inheritance example
76 #include <iostream.h>
77 #include "base1.h"
78 #include "base2.h"
79 #include "derived.h"
80
81 int main()
82 {
83   Base1 b1( 10 ), *base1Ptr = 0;  // create Basel object
84   Base2 b2( 'Z' ), *base2Ptr = 0; // create Base2 object
85   Derived d( 7, 'A', 3.5 );      // create Derived object
86
87   // print data members of base class objects
88   cout << "Object b1 contains integer "<< b1.getData()
89        << "\nObject b2 contains character" << b2.getData()
90        << "\nObject d contains:\n" << d << "\n\n";
91
92 // print data members of derived class object
93 // scope resolution operator resolves getData ambiguity
94   cout << "Data members of Derived can be"
95        << "accessed imdividually:"
96        << "In   Integer: "<< d. Base1::getData()
97        << "\n Character:  << d. Base2::getData()
98        << "\nReal number: "<< d.getReal() << "\n\n";
99
100  cout << "Derived can be treated as an"
101       << "object of either base class:In";
102
103 // treat Derived as a Basel object
104  base1Ptr = &d;
105  cout << "base1Ptr->getData() yields"
106       << base1Ptr->getData() << '\n';
107
108 // treat Derived as a Base2 object
109  base2Ptr = &d;
110  cout << "base2Ptr->getData() yields"
111       << base2Ptr->getData() << endl;
112
113  return 0;
114 }

输出结果:
object bl contains integer 10
object b2 contains character z
object d contains:
   Integer: 7
   Character: A
Real number:3.5

Data members of Derived can be accessed individually:
   Integer: 7
   Character: A
Real number:3.5

Derived can be treated as an object of either base class:
baselPtr->getDataO yields 7
base2Ptr->getData() yields A

                                  图9.11  多重继承的程序

    在Derived中重载的流插入运算符通过派生类对象d用圆点表示法打印value、letter和real的值。因为该运算符函数是类Derived的友元,所以operator<<可以直接访问类Derived的private数据成员real,还能访问Base1和Base2的protected数据成员value和letter。
    下面探讨一下main函数中的驱动程序。程序中首先建立了类Base1的对象b1和类Base2的对象b2,并将它们分别初始化为int类型的值10和char类型的值'z',然后建立类Derived的对象d并将其初始化成包括int类型的值7、char类型的值'A'和float类型的值3.5。
    通过调用每个对象的getData函数打印每个基类对象的内容。尽管有两种getData函数,但是因为直接引用了对象b1和b2的getData函数版本,因此对它们的调用没有歧义性问题。
接下来用静态关联打印出Derived的对象d的内容。因为该对象包含两个getData函数,一个是从类Base1继承来的,另一个是从Base2继承来的,所以存在着歧义性问题。用二元作用域运算符很容易解决这个问题。例如,d.Base1::getData()打印了int类型的value值,d.Base2::getData()打印了char类型的letter值。调用d.getReal()打印float类型的real值不存在歧义性问题。然后演示了单一继承的“是”关系也适用于多重继承。程序中把派生类对象d的地址赋给了基类指针Base1Ptr,并用该指针调用Base1的成员函数getData打印出int value值。之后又把d的地址赋给基类指针Base2Ptr,并用该指针调用Base2的成员函数getData打印出charletter的值。
    这个例子展示了多重继承的机制并介绍了一种简单的歧义性问题。多重继承是一个很复杂的话
  题,许多高级C++书籍对此有详细的论述。

    软件工程视点9.12
    多重继承是个强大的功能,但可能增加系统的复杂性。使用多重继承的系统需要更加认真设计,能用单一继承时应尽量使用单一继承。


小  结
    ●面向对象的程序设计能力的关键之一是通过继承实现软件的复用。
    ●程序员可以让新类继承已定义基类的数据成员和成员函数,而不必重新编写新的数据成员和成员函数。这种新类称为派生类。
    ●对于单一继承,派生类只有一个基类。对于多重继承,派生类常常是从多个基类派生出来的,这些基类之间可能毫无关系。
    ●派生类通常添加了其自身的数据成员和成员函数,因而通常比基类大得多。派生类比基类更具体,它代表了一组外延较小的对象。
    ●派生类不能访问其基类的private成员,否则会破坏基类的封装性。但是,派生类能够访问基类的public成员和protected成员。
    ●派生类的构造函数总是先调用其基类构造函数来初始化派生类中的基类成员。
    ●调用析构函数的次序和调用构造函数的次序相反,因此派生类析构函数在基类析构函数之前调用。
    ●利用继承能够实现软件复用。软件复用缩短了程序的开发时间,促使开发人员复用已经测试和调试好的高质量的软件。
    ●可以用现有的类库实现继承。
    ●将来有一天,软件也可以像如今的硬件一样用标准的可复用组件进行构造。
    ●派生类不必访问基类的源代码,但是需要知道基类的接口和能够连接到基类的目标代码。
    ●派生类对象可作为其public基类的对象处理,但是反过来不行。
    ●基类和派生类之间具有层次关

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -