10.7 基类与派生类对象间的相互转换

    private派生时,外部无法访问通过派生类对象直接访问从基类继承来的任何成员,因此,private派生的使用较少,本节主要讨论public派生时基类与派生类对象间的相互转换。

    注意

    只考虑public派生,这样可以保证在派生类中对基类的public成员进行访问,没有加以特别的说明时,本节所说的基类和派生类均系public派生。

    10.7.1 类型适应

    “类型适应”是指两种类型之间的关系,说类A适应类B是指类A的对象能直接用于类B对象所能应用的场合,从这种意义上讲,派生类适应于基类,派生类的对象适应于基类对象,派生类对象的指针和引用也适应于基类对象的指针和引用。

    类型适应很大程度上减轻了程序编写的工作量,因为若一个函数可用于某类型的对象,则它也可作用于该类的所有派生类对象,不必再为处理派生类对象重载该函数。

    也就是说,形参要求为基类对象时,可以直接用派生类对象做实参,除此之外,类型适应还体现在以下两个方面。

    1.赋值转换

    可以用派生类对象为基类对象赋值,用派生类对象初始化基类对象的指针。派生类对象可以理解为包含了一个基类对象和一个附加子对象,因此,上述两种转换不会出现错误,但由于基类不适应派生类,因此,基类不能赋值给派生类,也不能用基类对象初始化派生类的引用。

    2.指针转换

    可以用派生类对象的地址初始化基类对象的指针,这时因为派生类对象与其基类分量具有相同的地址,如图10.8所示,将派生类的指针赋值给指向基类的指针时,便可通过此指向基类的指针访问派生类对象中从基类继承下来的成员。但对派生类中新加成员,除非采用强制类型转换,否则不可以用指向基类的指针来访问。

    同样的道理,把基类指针直接赋值给派生类指针是不允许的,必须通过强制转换的形式来完成,综合示例如代码10.8所示。

    10.7 基类与派生类对象间的相互转换 - 图1

    图 10.8 派生类的内存模型简图

    代码10.8 类型适应示例TypeSample


    <——————————文件名:example1008.cpp————————————————-> 01 #include<iostream> 02 using namespace std; 03 class A//类A定义 04 { 05 private: 06 int x; 07 public: 08 A(int xp=0)//构造函数 09 { 10 x=xp; 11 } 12 void dispA()//成员函数dispA的定义 13 { 14 cout<<"Hello,this is A and x:"<<x<<endl; 15 } 16 int GetX()//成员函数用以读取private成员x的值 17 { 18 return x; 19 } 20 }; 21 class B:public A//类B由类A派生而来 22 { 23 private://在基类A的基础上增加的数据成员 24 int y; 25 public: 26 B(int xp=1,int yp=1):A(xp)//构造函数,在初始化表中调用基类的构造函数 27 { 28 y=yp; 29 } 30 void dispB()//成员函数dispB 31 { 32 cout<<"Hello,this is B and x:"<<GetX()<<",y:"<<y<<endl; 33 } 34 }; 35 int main()//主函数 36 { 37 A pt1(1);//声明一个类A对象pt1 38 pt1. dispA();//通过pt1调用dispA函数 39 B pt2(2,3);//声明一个派生类对象pt2 40 pt2. dispB();//通过pt2调用dispB函数 41 pt1=pt2;//派生类对象为基类对象赋值 42 pt1. dispA(); 43 A&rpt1=pt2;//派生类对象初始化基类对象引用 44 rpt1. dispA(); 45 A*ppt1=&pt2;//派生类对象地址为基类指针赋值 46 ppt1->dispA(); 47 ((B*)ppt1)->dispB();//基类指针向派生类指针的强制转换 48 return 0; 49 }

    输出结果如下所示。


    Hello,this is A and x:1 Hello,this is B and x:2,y:3 Hello,this is A and x:2 Hello,this is A and x:2 Hello,this is A and x:2 Hello,this is B and x:2,y:3

    【代码解析】代码10.8中,在基类A的基础上派生了类B,代码第41行是由派生类B的对象向基类A对象赋值,用派生类B的对象初始化基类A的引用,用派生类地址为基类指针赋值都是合法的,如果要使用基类指针访问派生类中添加的成员,必须采用诸如“((B*)ppt1)”的强制转换形式,而且必须保证强制转换后的指针所指内存有效,见代码第47行。