5)如果基类中没有默认参数值的构造函数,则必须在派生类的构造函数中通过上述方式向相应的基类的构造函数传递参数。
6)构造函数的调用顺序只与派生类继承的基类的顺序有关,而与初始化成员列表中构造函数顺序无关,与派生类中参数的顺序也无关。
7) 如果基类A的派生类为B,B又派生了C,则在对B进行初始化之前,必须对它的基类A进行初始化,通常是通过B的构造函数实现。但是不能通过C的构造函数实现。即一个类的构造函数只能对它的直接基类的构造函数传递实参。对于更多层继承关系,都可按这种方式递归进行。
8 )如果派生类中包含对象成员,则创建派生类对象时,C++规定构造函数的调用次序为: 基类的构造函数、对象成员的构造函数、派生类的构造函数。
如果,此时基类中有对象成员,调用基类的构造函数之前还要先调用基类对象成员的构造函数,调用次序与前述类同。
在初始化成员列表中,对象成员采用的是对象名,而对基类的初始化使用的是基类的类名,即基类的构造函数名。
调用顺序如下图所示:
基类的基类的构造函数 基类对象成员的构造函 基类的构造函数 派生类对象的构造函数
派生类的构造函数
8.2.4 总结
派生方式(基类的被继承方式) 在基类中的存取权限 在派生类中的存取权限 ================================================== public public public public potected protected
public private (inaccessible) potected public potected potected potected protected potected private (inaccessible) private public private private potected private private private (inaccessible) ==================================================
派生类中可出现四种成员:
6
1) 不可访问的成员 -- 基类的private私有成员被继承过来后,这些成员在派生类中是不可访问的。
2) 私有成员 -- 包括在派生类中新增加的private私有成员以及从基类私有继承过来的某些成员。这些成员在派生类中是可以访问的。
3) 保护成员 -- 包括在派生类中新增加的potected保护成员以及从基类继承过来的某些成员。这些成员在派生类中是可以访问的。
4) 公有成员 -- 包括在派生类中新增加的public公有成员以及从基类公有继承过来的基类的public成员。这些成员不仅在派生类中可以访问,而且在建立派生类对象的模块中,也可以通过对象来访问它们。
8.2.5 例题
(8.2.1 派生类的说明)例题
1.公有派生
如果访问属性是为public,则基类的public成员是派生类的public成员;基类的protected成员是派生类的protected成员;基类的private成员是派生类的private成员;即基类的private成员对派生类仍保持private属性。
显然,派生类中通过公有派生得到的成员还可以被它的子类继承。 例1:公有派生中各成员的访问权限 # include
int z ;
CBase (int a , int b , int c) {x=a ;y=b; z=c;}
int Getx (void ) {return x ;} int Gety (void ) {return y ;} void ShowBase (void)
{ cout<<”x=”< }; class CDerived :public CBase { int Length ,Width ; public : CDerived ( int a , int b ,int c ,int d , int e) :CBase(a,b,c) //A 表示派生类的构造函数调用 //基类的构造函数,从而对继承得到的基类的成员进行初始化。见11.2节。 { Lengh=d ; Width=e ;} void Show (void ) { cout<<”Length=”< cout<<”x=”< int Sum (void) { return Gex ( )+y+z+Length+Width ; } 7 }; void main ( void ) { CDerived d1 (1 ,2,3,4,5) ; d1.ShowBase( ) ; //E,公有成员函数,可以被继承为公有。 d1.show ( ) ; cout<<”sum=”< cout<<”y=”< 执行结果: x=1 y=2 z=3 Length=4 Width=5 x=1 y=2 z=3 Sum=15 y=2 z=3 2.私有派生 如果访问属性为private,则基类的public和protected成员都是派生类的private成员;这些私有成员能够被派生类的成员函数直接访问;但在派生类之外不可以被直接访问。但基类的private成员对派生类仍然保持private属性,即不能被派生类成员函数访问。总之当访问属性为private时,派生类的对象不能访问基类中以任何方式定义的成员函数。 显然通过私有派生得到的派生类再派生子类时,其继承得到的基类成员不能被它的子类所继承。 例2: 私有派生示例 # include int b ; void Set (int x ,int y) {a=x ; b=y ;} void Show ( void ) {cout< }; class CDerived :private CBase { public: void SetD(int x , int y) {Set (x , y) ;} void ShowD(void) {cout< } ; void main ( ) 8 { CBase b1 ; CDerived d1 ; b1.Set (1 ,2) ; b1.Show( ) ; d1.SetD(10 ,100 ) ; //若d1.set(10 , 100) 则错误,因为set()被私有继承,不能被访问 d1.ShowD( ) ; // d1.Show ( ) 则错误,同上 } 执行结果: 1 2 10 100 假如,还有一个类CCD由派生类CDerived派生出来,定义如下: class CDD :public Cderived { --- //类体 } 则CDD的类体中的成员不能访问CDerived从基类CBase私有继承来的成员,因为这些成员是类CDerived的私有成员,他们不能被类CDD所继承。当然对类CDerived中的保护成员和公有成员在类CDD中仍然可以被访问。 3.保护派生 如果访问属性为protected,则基类的public和protected成员均是派生类的protected成员;基类的private成员对派生类仍保持private属性。具体来说,基类中声明为protected的数据只能被基类的成员函数或其派生类的成员函数访问;不能被派生类以外的成员函数访问。 对保护派生,基类中的公有成员和保护成员在派生类中均变为保护成员,它们仍然可被它的子类所继承。 例3 # include void setab (int n ,int m) {a=n ; b=m;} }; class derive :public base { int c ; public: void setc (int n) {c= n;} void showabc() {cout< 9 { derive obj ; obj.setab(2,4); obj.setc(3); obj.showabc(); return 0 ; } 执行结果: 2 4 3 Press any key to continue 例4 私有继承方式的保护成员 # include void seta(int sa) {a=sa ;} }; class derive 1:private base { protected : int b ; public: void setb(int sb) {b=sb ;} }; classs derive2:public derive1 { int c ; public: void setc(int sc) {c=sc;} void show() { cout<<\< void main() { base op1 ; op1.seta(1) ; derive1 op2 ; op2.setb(2 ) ; derive2 op3 ; 10