理解基类类型和派生类之间的转换,对于理解面向对象编程在C++中如何工作非常关键。
每个派生类对象都包含了一个基类的部分,这意味着可以像使用基类对象一样在派生类对象上执行操作。因为派生类对象也是基类对象,所以存在从派生类对象的引用到基类对象引用的转换,对指针类似。
基类类型对象既可以作为独立部分存在,也可以作为派生类对象的一部分而存在,因此一个基类对象可能也可能不是派生对象的部分,结果没有从基类引用(或基类指针)到派生类引用(或派生类指针)的(自动)转换。
相对于引用或或指针而言,对象转换的情况更为复杂。虽然一般可以使用派生类型的对象对基类对象进行初始化或赋值,但是没有从派生类型对象到基类类型对象的直接转换。
一.派生类到基类的转换
如果有一个派生类对象,则可以使用他的地址对基类类型的指针进行赋值或初始化。同样可以使用派生类型的引用或对象初始化基类类型的引用。严格来说,对对象没有类似转换。编译器不会自动将派生类型对象转换为基类类型的对象。
但是一般可以使用派生类型对象对基类对象进行初始化,对对象进行初始化或赋值以及可以自动转换引用或指针,这之间的关系式微妙的,必须好好理解。
1.引用转换不同于转换对象
将对象传递给希望接受引用的函数时,引用直接绑定到该对象。虽然看起来是在传递对象,但是实际上实参是该对象的引用,对象本身未被复制,并且转换不会在任何方面改变派生类型的对象,该对象认识派生类型的对象。
将派生类对象传递给接受基类类型对象(而不是引用)的函数时,情况完全不同。在这种情况下,形参的类型是固定的——在编译和运行时形参都是基类类型对象。如果用派生类对象调用这样的函数,则派生类对象的基类部分被复制到形参。
2.用派生类对象对基类对象进行初始化或赋值
对基类对象进行初始化或赋值,实际上是在调用函数:初始化是在调用构造函数,赋值是在调用赋值操作符。
用派生类对象对基类对象进行初始化或赋值,有两种可能。第一种(虽然不太可能)可能性是,基类科恩能够显式定义了将派生类类型对象赋值或复制到基类对象的方法,这可以通过定义适当的构造函数或赋值操作符来实现:
class Derived ;
class Base
{
public:
Base (cosnt derived & ) ;
Base & operator = ( const Derived & ) ;
......
} ;
在这种情况下,这些成员的定义将控制用Derived对象对Base对象进行初始化或赋值时将发生什么。
第二种情况的分析先看代码:
因为存在从派生类引用到基类引用的转换,赋值控制成员可用于从派生类对象对基类对象进行初始化或赋值。
用Bulk_item类型的对象调用Item_Base类的复制构造函数或赋值操作符时,将发生下列步骤:
a.将Bulk_item对象转换为Item_base引用,这仅仅意味着将一个Item_Base引用绑定到bulk_item对象。
b.经该引用作为实参传递给复制构造函数或赋值操作符
c.那些操作符使用Bulk_Item的Item_Base的部分分别对调用构造函数或赋值的Item_Base对象的成员进行初始化或者赋值。
d.一旦操作符执行完毕,对象即为Item_base。它包含Bulk_item的Item_Base部分的副本,但实参的Bulk_item部分被忽略。