一 继承的基本概念
系统提供了相当多的已定义好的基类,用户可以根据具体的应用,在已有类的基础上构架新类,在派生类中,可以直接使用父类部分的代码,但却不需要重新编写父类的代码。这样可以加速软件开发的速度,保障软件开发的质量。继承提供了在已有类的基础上开发出新类的机制,可以节省重复代码的编写工作,是软件重用的基础。
已知一个类A,对A类加以扩展,即增加一些属性和行为,构成一个新类B,此时B类将A类已有的属性和行为继承下来。称类 B 继承了 A ,或称类 A 派生了 B 。A:父类,基类,B:子类,派生类。
在c++中有两种继承:
1、单一继承 |
2、多重继承 |
二、单一继承
class <派生类名>: <继承方式> <基类名>
{
[private: // 私有成员说明
...]
[public: // 公有成员说明
...]
[protected: // 保护成员说明
...]
} ;
2.1继承方式:
1、public公有继承 |
2、private私有继承 |
3、protected保护继承 |
2.2公有继承:
class A
{ ......
};
class B: public A // 公有继承A
{ ......
};
A中的: | 在B中的: | 在B的类外(通过对象) |
private成员 | 不可访问 | 不可访问 |
public 成员 | 认为public成员 | 可访问 |
protected成员 | 仍为protected成员 | 不可访问 |
2.3私有继承:
class A
{ ......
};
class B: private A // 私有继承A
{ ......
};
A中的: | 在B中的: | 在B的类外(通过对象) |
private成员 | 不可访问 | 不可访问 |
public 成员 | 变为private成员 | 不可访问 |
protected成员 | 仍为private成员 | 不可访问 |
2.4保护继承:
class A
{......
};
class B: protected A // 保护继承A
{ ......
};
A中的: | 在B中的: | 在B的类外(通过对象) |
private成员 | 不可访问 | 不可访问 |
public 成员 | 变为protected成员 | 不可访问 |
protected成员 | 仍为protected成员 | 不可访问 |
2.5private成员和peotected成员的呢区别
无论何种继承方式,private成员是无法在派生类中被直接访问的。
而对于protected成员,根据不同的派生方式,protected成员的直接访问特性可以被(或不被)传递到派生类的派生类中。
1)对于公有派生,基类的protected成员在派生类中依然保持protected属性。
2)对于私有派生,基类的protected成员在派生类中变成了private成员,此时基类的protected成员就再也无法在派生类的派生类中被直接访问了。在继承或派生链中,一旦出现私有继承,则父类的成员的“类内直接访问特性”就无法在后面的派生中传递下去。
3)对于保护派生,基类的protected成员在派生类中依然保持protected属性,此时情况与公有派生类似。
类中protected成员的优点是:既可以在本类中实现数据的隐藏(在类外不可被直接访问),又可以将其类内直接访问特性传递到派生类中(在派生类中可直接访问)。但private成员只能实现本类中的数据隐藏,而不能将其类内直接访问特性传递到派生类中
三、多重继承:
class <派生类名>: <继承方式1> <基类名1>,
<继承方式2> <基类名2>,
…
{ //以下定义派生类新成员
[private: // 私有成员说明
... ]
[public: // 公有成员说明
... ]
[protected: // 保护成员说明
... ]
} ;
多重继承,继承多种方式。
四、基类成员的初始化
1. 基类的构造函数和析构函数的调用顺序
若一个类是由多个基类派生出来的,则在定义派生类构造函数时,应调用基类的构造函数,以初始化基类成员。
派生类构造函数的一般格式:
ClassName :: ClassName(args) : Base1(arg1) , Base2(arg2) , ...... , Basen(argn)
{ <派生类自身的构造函数体> } ;
其中ClassName是派生类名,Base1、Base2、...Basen为基类的类名。args是派生类自身的构造函数的形参列表,arg1、arg2、...argn是调用基类构造函数的实参列表。
构造函数的调用顺序为:Base1( )、 Base2( )、...... Basen( )、最后执行<派生类自身的构造函数体>。
析构函数的调用顺序为:(相反)先执行派生类自身的析构函数体、然后按 ~ Basen( ) 、……~Base2( ) 、~Base1( )。
2. 对象成员构造函数和析构函数的调用顺序
若派生类中包含对象成员,则在派生类的构造函数的初始化成员列表中,不仅要列举基类的构造函数,而且要列举对象成员的构造函数。先调用基类的构造函数,再调用对象成员的构造函数,最后执行对象自身的构造函数。