类其实也是一种数据类型,也可以发生数据类型转换,不过这种转换只有在基类和派生类之间才有意义,并且只能将派生类赋值给基类,包括将派生类对象赋值给基类对象、将派生类指针赋值给基类指针、将派生类引用赋值给基类引用,这在 C++ 中称为向上转型(Upcasting)。相应地,将基类赋值给派生类称为向下转型(Downcasting)。

赋值的本质是将现有的数据写入已分配好的内存中,对象的内存只包含了成员变量,所以对象之间的赋值是成员变量的赋值,成员函数不存在赋值问题。
将派生类对象赋值给基类对象时,会舍弃派生类新增的成员,所以不存在安全问题。
即使将派生类对象赋值给基类对象,基类对象也不会包含派生类的成员,所以依然不能通过基类对象来访问派生类的成员。

这种转换关系是不可逆的,只能用派生类对象给基类对象赋值,而不能用基类对象给派生类对象赋值。理由很简单,基类不包含派生类的成员变量,无法对派生类的成员变量赋值。同理,同一基类的不同派生类对象之间也不能赋值。

将派生类指针赋值给基类指针时,通过基类指针只能使用派生类的成员变量,但不能使用派生类的成员函数

注意:
向上转型:
将派生类类型的指针或引用转换为基类类型的指针或引用。这种操作性缩小的类型转换,在编译器看来是安全的,因此可以隐式完成。
向下转型:
将基类类型的指针或引用转换为派生类类型的指针或引用。这种操作性扩大的类型转换,在编译器看来是危险的,因此必须显示的完成。

向上转型(跟虚函数多态相关联)

在C++中,public继承时,如果B是A的派生类,那么B的对象就可以被当作A的对象来看待,称之为向上转型。
派生类对象具有基类对象所具有的绝大部分成员, 除了基类的私有成员.

向上转型 - 图1
比如将派生对象看成基类对象 Base* A= new Derived(), 则A.derived_member只能访问基类对象的成员变量和成员函数,如果需要根据实际的对象来调用相应的成员变量和成员函数,则需要用到动态绑定即给基类相关变量和方法标注virtual虚函数来实现动态绑定(多态)

那么如何理解向上转型呢?

面向对象编程有三个特征,即封装、继承和多态。

  • 封装:隐藏了类的内部实现机制,从而可以在不影响使用者的前提下改变类的内部结构,同时保护了数据。
  • 继承:是为了重用基类代码,同时为实现多态性作准备。那么什么是多态呢?
  • 多态:方法的重写、重载与动态连接构成多态性。此外,抽象类和接口也是解决单继承规定限制的重要手段。同时,多态也是面向对象编程的精髓所在。

向上转型
定义了一个派生类Cat,它继承了Animal类,那么后者就是前者是基类。我可以通过

  1. Cat c = new Cat();

实例化一个Cat的对象,这个不难理解。但当我这样定义时:

  1. Animal a = new Cat();


这表示定义了一个Animal类型的引用,指向新建的Cat类型的对象。由于Cat是继承自它的基类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。那么这样做有什么意义呢?因为派生类是对基类的一个改进和扩充,所以一般派生类在功能上较基类更强大,属性较基类更独特。基类类型的引用可以调用基类中定义的所有属性和方法,而对于派生类中定义而基类中没有的方法,它是无可奈何的