类型转换与继承
2024年1月5日 2024年1月5日
我们可以使基类的指针和引用指向/绑定到派生类对象
使用基类的指针和引用时, 我们并不清楚对象的真实类型
智能指针也支持派生类向基类的类型转换
静态类型与动态类型
当我们使用存在继承关系的类型时, 需区分静态类型 static type
和动态类型 dynamic type
.
表达式的静态类型在编译时已知, 或是变量类型, 或是表达式类型; 动态类型则是内存中对象的类型, 直到运行时才可知
编译器可以判断表达式的静态类型,但无法索骥变量的动态类型
如果表达式不是引用和指针, 它的动态类型永远与静态类型一致
不存在从基类到派生类的隐式类型转换
派生类对象包含基类部分, 反过来是不可能的
1Quote base; 2Bulk_quote *bulkP = &base; // 错误 3Bulk_quote &bulkRef = base; // 错误
编译器只能通过检查指针或引用的静态类型来推断转换是否合法
1Bulk_quote bulk; 2Quote *itemP = &bulk; 3Bulk_quote *bulkP = itemP; // 错误: 编译器在编译时无法确定某个特定的转换在运行时是否安全
如果程序员负责保证基类到派生类的静态转换合法, 可以使用dynamic_cast请求类型转换, 该转换的安全检查将在运行时执行
如果已知某个基类到派生类的转换是安全的, 可以直接使用static_cast, 强制覆盖编译器的检查工作
对象之间不存在类型转换
派生类向基类的自动类型转换只对指针或引用类型有效, 在派生类类型和基类类型之间不存在这样的转换
接受引用的拷贝构造函数和拷贝赋值运算符
- 拷贝构造函数和拷贝赋值运算符通常只包含一个参数, 具有底层const的类类型引用
- 构造函数是不能作为虚函数的, 拷贝赋值运算符通常不会被定义为虚函数
- 当我们向基类的拷贝构造函数和拷贝赋值运算符传入派生类对象时, 不会发生动态绑定, 使用的是基类的定义
构造函数构造一个基类对象, 赋值运算符只处理基类成员
1Bulk_quote bulk; 2Quote item(bulk); // Quote::Quote 3item = bulk; // Quote::operator=
上述过程会忽略Bulk_quote部分, 所以我们可以说bulk的Bulk_quote部分被切掉 sliced down
了
当我们用一个派生类对象为一个基类对象初始化或赋值时, 只有派生类对象的基类部分会被拷贝, 移动或赋值, 其派生类部分将被忽略掉
存在继承关系的类型之间的转换规则
- 从派生类到基类的类型转换只对指针和引用有效
- 不存在基类到派生类的隐式类型转换
- staic_cast
- dynamic_cast
- staic_cast
- 派生类到基类的类型转换可能由于访问受限而不可行
要求派生为public
可以将派生类对象拷贝, 移动或赋值给一个基类对象