}
ob0.priDat=3; //ERROR!不可以访问private成员 D11 d11;D21 d21; D22 d22;D23 d23;
d11.pubDat=4; //OK! 可以访问public成员
d11.proDat=5; //ERROR! 不可以访问protected成员 d11.priDat=6; //ERROR! 不可以访问private成员 d21.pubDat=7; ///OK! 可以访问public成员
d21.proDat=8; //ERROR! 不可以访问protected成员 d21.priDat=9; //ERROR! 不可以访问private成员
d22.pubDat=7; //ERROR! 不可以访问protected成员 d22.proDat=8; //ERROR! 不可以访问protected成员 d22.priDat=9; //ERROR! 不可以访问private成员 d23.pubDat=10; //ERROR! 不可以访问private成员
8. 3 其他特征的继承关系
8.3.1 友元关系以及静态成员的继承 8.3.1.1 友元关系
①. 基类的友元不被继承。
即如果基类有友元类或友元函数,则其派生类不会因继承关系也一定有此友元类或友元函数。
②.如果基类是某类的友元,则这种友元关系是被继承的。 即 被派生类继承过来的成员,如果原来是某类的友元,那么它作为派生类的成员仍然是某类的友元。
8.3.1.2 静态成员的继承
如果基类的静态成员被派生类继承,其静态属性也随静态成员被继承。
即 如果基类的静态成员是公有的或保护的,则它们被其派生类继承为派生类的静态成员。 ①.这些成员通常用“<类名>::<成员名>方式引用或调用。
②.无论有多少个对象被创建,这些静态成员都只有一个拷贝。它为基类和派生类的所有对象所共享。
8.3.2 与基类对象和派生类对象相关的赋值兼容性问题 8.3.2.1 基类和派生类中的赋值运算符的使用
①.如果派生类有自己的赋值运算符的重载定义,按该重载函数处理。
②.如果派生类未定义自己的赋值操作,而基类定义了赋值操作,则系统自动定义派生类赋值操作,其中基类成员的赋值按基类的赋值操作进行。
③.基类和派生类都未定义专门的赋值操作,系统自动定义缺省赋值操作(按位进行拷贝)。
8.3.2.3 基类对象和派生类对象的赋值兼容
基本数据类型,当两个变量的类型不一致时,只要相互之间兼容也可以进行赋值,比如可以将一个实型数据赋给整型变量。
同样,同类型的对象之间可以互相赋值:
在具有继承关系的类之间,公有派生对象可以直接赋值给基类的对象;之后基类对象
21
只能访问派生类中从基类继承的公有成员,不能访问派生类中增加的公有成员。
但私有派生类对象或保护派生类对象不可以赋给基类对象; 基类对象不可以赋给派生类对象;
公有派生类对象的地址可以赋给基类指针变量;公有派生类对象可以初始化基类引用。
即:
①基类对象=派生类对象 。 反之不行。
②指向基类对象的指针=派生类对象的地址 。反之不行。 ③基类的引用=派生类对象 。反之不行。
例1 . 赋值兼容规则 # include
CBase (int a){x=a ;} void Show1()
{cout<<”x=”< class CDerived :public CBase {protected: int y ; public : CDerived(int a , int b ):CBase (b) { y=a ;} void Show1() {cout<<”y=”< {cout<<”y=”< void main ( ) {CDerived c (2 ,3) ; CBase b1 (4) , *b2 ; CBase &b3=c ; //A 派生类对象初始化基类引用 b1=c ; //B 派生类对象赋给基类对象 b2=&c ; //C 派生类地址赋给基类指针 b1.Show1( ); //D b2->Show1( ) ; //E b3.Show1( ) ; //F // c=b1 ; //错误,不能将基类对象赋给派生类对象 //b1.Show2() ; //错误,不能访问派生类中增加的成员 //b2->Show2() ; //错误,理由同上 //b3.Show2() ; //错误,同上 执行结果: 22 x=3 x=3 x=3 //例 program 8-4 .cpp P264 #include base(int sa) { a=sa;} int geta() {return a;} }; class derived:public base //派生类 { int b; public: derived( ) { } derived(int sa, int sb):base(sa) { b=sb; } int getb() {return b;} }; void main( ) { base bs1(123); // 基类base的对象 cout<< \ derived der(246,468); // derived类的对象 bs1=der; //OK! cout<< \ //der=bs1; //ERR! base *pb = &der; //OK! ②指向基类对象的指针=派生类对象的地址 cout<<\ //OK! //cout< cout<<\//OK! -- 经过类型转换 //derived *pd = &bs1; //ERR! } /* bs1.geta()=123 bs1.geta()=246 pb->geta()=246 ((derived *)pb)->getb()=468 Press any key to continue */ 8.4 派生关系中的二义性处理 23 继承和派生把不同的类联系到一起,就产生了一个同名成员的处理问题,有下面几种情况。 8.4.1 单一继承时基类与派生类间重名成员的处理 在派生类中新增加的成员可以与基类的成员同名,这种同名不会产生冲突。 C++规定,当没有对这类成员指定作用域时,在派生类中所使用的这类成员为在派生类中定义的成员,即这时就好象派生类中定义的成员覆盖了从基类中继承的同名成员,因此这种关系称为成员覆盖(overridden),或称为支配规则。 在派生类中如果要使用这种隐藏了的成员、方法时利用作用域运算符,格式为: <基类名>::<成员名> 即 ①派生类的成员函数访问重名成员时;派生类的对象访问重名成员时, 不加类名限定时,默认为派生类中定义的成员。 ②上述情况下,如果要使用这种隐藏了的成员、方法时利用作用域运算符,格式为: <基类名>::<成员名> 例1.成员覆盖示例 # include { protected : int x ; public : void Show (void) {cout<<”基类B中的x=”< class D:public B //E 公有派生 { protected: int x ; public: void Show ( ) {cout<<”派生类D中的x=”< {x=a ;} //F覆盖了基类的x,不会产生二义性。 void SetBX (int a ) {B::x=a ;} //G利用作用域运算符访问继承类B中的成员。 void ShowB ( ) {B::Show() ;} //H同G } ; void main (void) {D c; c.SetX(20) ; c.SetBX(30) ; c.Show() ; //I,访问是类D的成员 c.B::Show (); //J同G,此处若不是公有派生,而是私有派生,则会出错。 } 24 执行结果: 派生类D中的x=20 基类B中的x=30 //例2.program 8-5. cpp P266 #include CB(int x){a=x;} void showa(){cout<<\}; class CD:public CB { public: int a; //与基类a同名 CD(int x, int y):CB(x){a=y;} void showa(){ //与基类showa同名 cout<<\ } void print2a() { cout<<\ //子类a cout<<\ //父类a } }; void main() { CB CBobj(12); CBobj.showa(); CD CDobj(48, 999); CDobj.showa(); //子类的showa CDobj.CB::showa(); //父类的showa cout<<\ cout<<\ } /* Class CB -- a=12 Class CD -- a=999 Class CB -- a=48 CDobj.a=999 CDobj.CB::a=48 Press any key to continue */ 8.4.2 多重继承时两基类间重名成员的处理 25