继承
类之间的继承
可以扩展 C + + 中的类,即创建保留基类特征的新类。这个过程称为继承,涉及一个基类和一个派生类: 派生类继承基类的成员,在这些成员之上派生类可以添加自己的成员。
例如,让我们想象一系列的类来描述两种多边形: 矩形(rectangles)和三角形(triangles)。这两个多边形有一些共同的属性,例如计算它们的面积所需的值: 它们都可以简单地用高度和宽度(或基数)来描述。
这可以在类的世界中用一个Polygon
类来表示,我们可以从这个类派生出另外两个多边形: 矩形( Rectangle
)和三角形(Triangle
):
Polygon 类将包含多边形所具有的一些通用的成员。如在我们的例子中: 宽度和高度。矩形和三角形将是它的派生类,具有各自特定特征。
从其他类派生的类继承基类的所有可访问成员。这意味着如果一个基类包含一个成员 A,并且我们从它派生一个包含另一个成员 B 的类,那么派生的类将同时包含成员 A 和成员 B。
两个类的继承关系在派生类中声明:class derived_class_name: public base_class_name { /*...*/ };
- 其中
derived_class_name
是派生类的名称,base _ class _ name 是它所继承的基类的名称。公共访问说明符也可以由其他访问说明符(protected
或private
)。
// 派生类
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b;}
};
class Rectangle: public Polygon {
public:
int area ()
{ return width * height; }
};
class Triangle: public Polygon {
public:
int area ()
{ return width * height / 2; }
};
int main () {
Rectangle rect;
Triangle trgl;
rect.set_values (4,5);
trgl.set_values (4,5);
cout << rect.area() << '\n';
cout << trgl.area() << '\n';
return 0;
}
- 矩形和三角形类的对象都包含从
Polygon类
继承的成员,这些对象是: width、 height 和 set _ value。 - 类 Polygon 中使用的
private
访问说明符类似于 private。其唯一的区别实际上与继承有关: 当一个类继承另一个类时,派生类的成员可以访问从基类继承的private
成员,但不能访问其私有(private)成员。 - 通过将 width 和 height 声明为 protected 而不是 private,这些成员也可以从派生类 Recangle 和 Triangle 访问,而不仅仅是从 Polygon 的成员访问。如果它们是公共的,那么可以从任何地方访问它们。
我们可以总结出不同的访问类型,根据这些类型,函数可以通过以下方式访问它们:
访问 | public | protected | private |
---|---|---|---|
类内成员 | yes | yes | yes |
派生类成员 | yes | yes | no |
非成员 | yes | no | no |
- 其中“非成员”表示来自类外部的任何访问,例如来自 main、来自另一个类或函数的访问。
在上面的示例中,由矩形和三角形继承的成员拥有与其基类 Polygon 相同的访问权限:
Polygon::width // protected access Rectangle::width // protected access Polygon::set_values() // public access Rectangle::set_values() // public access
- 这是因为在每个派生类上使用 public 关键字声明了继承关系:
class Rectangle: public Polygon { /* ... */ }
- 由于 public 是最可访问的级别,因此通过指定此关键字,派生类Recangle将继承与基类中具有相同级别的所有成员。
使用 protected 时,基类的所有公共(public)成员在派生类中继承为 protected。相反,如果指定了最受限制的访问级别(private) ,则所有基类成员都将作为 private 继承。
例如,如果daughter是从mother派生的类,我们定义为:
class Daughter: protected Mother;
- 如果没有为继承指定访问级别,则编译器为类的假定关键字为 private,而struct 的继承默认为 public。
- 实际上,C + + 中的大多数继承用例都应该使用public继承。
从基类继承什么?
原则上,公共派生类继承基类的每个成员,除了:
- 它的构造函数和析构函数
- 其赋值运算符成员(运算符 =)
- 它的友元
- 它的私有成员
即使对基类的构造函数和析构函数的访问不是继承的,它们也会被派生类的构造函数和析构函数自动调用。
除非另有说明,否则派生类的构造函数将调用其基类的默认构造函数(即不带参数的构造函数)。使用初始化列表中用于初始化成员变量的相同语法,可以调用基类的另一个构造函数:
- 初始化列表:就是在参数列表()与构造函数主体{}之间初始化的一种语法格式,使用冒号:,多个初始化用逗号隔开。
derived_constructor_name (parameters) : base_constructor_name (parameters) {...}
例如:
// 构造函数与派生类 || constructors and derived classes
#include <iostream>
using namespace std;
class Mother {
public:
Mother ()
{ cout << "Mother: no parameters\n"; }
Mother (int a)
{ cout << "Mother: int parameter\n"; }
};
class Daughter : public Mother {
public:
Daughter (int a)
{ cout << "Daughter: int parameter\n\n"; }
};
class Son : public Mother {
public:
Son (int a) : Mother (a)
{ cout << "Son: int parameter\n\n"; }
};
int main () {
Daughter kelly(0);
Son bud(0);
return 0;
}
输出结果:
Mother: no parameters Daughter: int parameter Mother: int parameter Son: int parameter
请注意在创建新的 Daughter 对象时调用 Mother 的构造函数与在创建 Son 对象时调用 Mother 的构造函数之间的区别。区别在于 Daughter 与 Son 的构造函数声明不同:
Daughter (int a) //
没有特别说明: 调用默认构造函数
Son (int a) : Mother (a) //
调用这个特定的构造函数(有参构造)
多重继承
一个类可以通过简单地指定更多的基类(用逗号分隔)来继承不止一个类。例如,再继承在屏幕上打印 Output 的特定类,我们可以写:
class Rectangle: public Polygon, public Output;
class Triangle: public Polygon, public Output;
完整的示例:
// 多重继承 || multiple inheritance
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
Polygon (int a, int b) : width(a), height(b) {}
};
class Output {
public:
static void print (int i);
};
void Output::print (int i) {
cout << i << '\n';
}
class Rectangle: public Polygon, public Output {
public:
Rectangle (int a, int b) : Polygon(a,b) {}
int area ()
{ return width*height; }
};
class Triangle: public Polygon, public Output {
public:
Triangle (int a, int b) : Polygon(a,b) {}
int area ()
{ return width*height/2; }
};
int main () {
Rectangle rect (4,5);
Triangle trgl (4,5);
rect.print (rect.area());
Triangle::print (trgl.area());
return 0;
}
输出结果:
20 10