声名一个子类(派生类)的一般格式:
class 子类名:[继承方式]父类名
{
子类新增的数据成员和成员函数
};
继承方式有:private、protected、public(私有继承、保护继承、公有继承)
如果不显示的说明子类的继承方式,系统将默认继承方式为private(私有继承)
子类继承父类的方式,决定了子类中新的成员函数以及子类的对象对从父类继承来的成员的访问权限。
子类(派生类)的构成:
子类中的成员包括从父类继承来的成员和自己增加的成员两大部分。每一部分均包括了数据成员和成员函数。
从一个父类派生出来的子类,从父类那里继承来相同的数据和函数,这是共性,每个子类又有自己新增的数据和函数,这是个性。
事实上,并不是把积累的成员和派生类新增的成员简单的加在一起就构成了派神类,构造一个派生类一般要包括3个部分的工作:
(1)派生类从基类接收成员
在C++的类继承中,派生类将基类除构造函数和析构函数以外的所有成员接收。
(2)调整从基类接收来的成员
派生类不能选择从基类接收哪些成员,但是可以对接收到的成员做一些调整。调整包括两方面:
①改变基类成员在派生类中的访问属性。这主要是通过派生类声名时的继承方式来控制的。除此之外还有一些特殊的方式,将在后文提到。
②对基类的成员进行重定义。即在派生类中声名一个与基类成员同名的成员,则派生类中新的新成员会覆盖基类中的同名成员,此时在派生类中或者通过派生类对象,直接使用成员名就只能访问到派生类中声名的同名成员。需要注意的是,如果想要对基类中的成员函数进行重定义,不仅函数名要相同,函数的参数表也应该相同,否则定义的函数只是重载了基类的成员函数,而不是覆盖了基类的同名成员函数。
(3)在派生类中增加新成员
在派生类中增加新成员体现了派生类对基类功能的扩展,是继承和派生机制的核心。
由于在继承的过程中,基类的构造函数和析构函数不能被继承,所以一般需要在派生类中定义新的构造函数和析构函数,提供间接调用基类构造函数、析构函数的接口。
基类成员在派生类中的访问属性:
派生类可以继承基类中除了构造函数和析构函数之外的成员,但这些成员的访问属性在派生过程中是可以调整的,调整的主要方式是在继承时指定继承的方式,其他的调整方式还有同名成员和访问声名等。
在派生类中,从基类继承来的成员的访问属性有:公有、保护、私有、不可直接访问。
基类中的成员 | 公有派生类中的访问属性 | 保护派生类中的访问属性 | 私有派生类中的访问属性 |
私有成员 | 不可直接访问 | 不可直接访问 | 不可直接访问 |
保护成员 | 保护 | 保护 | 私有 |
公有成员 | 公有 | 保护 | 私有 |
归纳总结:
不论用什么方式继承基类,基类中的私有成员在派生类中都是不能直接访问的,只能通过基类中非私有属性的函数实现间接访问。换句话说,类中的私有成员,既不能被类的派生类成员访问,也不能被派生类的函数访问,是能被类自己的函数访问,一般来说,设计基类时,总是要为它的私有数据成员提供公有的成员函数进行访问,以便派生类可以间接的访问到这些数据成员。
派生类中的构造函数和析构函数:
派生类继承了基类的成员,实现了代码的重用,但这仅仅是引入继承的目的之一。引入继承的更主要的目的是实现代码的扩充,只有在派生类中添加新的数据成员,加入新的成员函数,类的派生才有意义。
C++中派生类构造函数的一般格式:
派生类名(参数总表): 基类名(参数表)
{
派生类新增的数据成员的初始化语句
}
参数总表中包含了所有基类构造函数需要的参数:
类型1 参数1,类型2 参数2,...,类型n 参数n
基类名(参数表) 实际上是在间接调用基类的构造函数,所以参数表的形式:
参数1,参数2,参数n
从参数的类型看,参数总表中的参数是形式参数,参数表中的参数是实际参数。基类构造函数中的参数可以来源于参数总表,也可以是指定的常数值。
需要注意的是,在如果构造函数在类外定义,在类中声名构造函数时,不需要将基类构造函数名和参数列表列出来。
当基类构造函数不带参数时,派生类不一定要定义构造函数,然而当基类的构造函数哪怕只带一个参数,它的所有派生类都必须定义构造函数,甚至派生类的构造函数函数体为空,仅仅为了传递参数给基类的构造函数。
构造函数严格的按照先调用基类构造函数后调用派生类构造函数的顺序执行。析构函数的执行顺序与之相反。
含有对象成员的派生类的构造函数的一般形式:
派生类名(参数总表):基类名(参数表),对象成员1(参数表),...,对象成员n(参数表n)
{
派生类新增成员的初始化语句
}
构造函数的执行顺序:
①基类构造函数
②对象成员的构造函数
③派生类的构造函数
撤销对象时,调用析构函数的顺序与之相反。