六一的部落格


关关难过关关过,前路漫漫亦灿灿。



我们可以使基类的指针和引用指向/绑定到派生类对象

使用基类的指针和引用时, 我们并不清楚对象的真实类型

智能指针也支持派生类向基类的类型转换


静态类型与动态类型

当我们使用存在继承关系的类型时, 需区分静态类型 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, 强制覆盖编译器的检查工作


对象之间不存在类型转换

派生类向基类的自动类型转换只对指针或引用类型有效, 在派生类类型和基类类型之间不存在这样的转换


接受引用的拷贝构造函数和拷贝赋值运算符

  1. 拷贝构造函数和拷贝赋值运算符通常只包含一个参数, 具有底层const的类类型引用
  2. 构造函数是不能作为虚函数的, 拷贝赋值运算符通常不会被定义为虚函数
  3. 当我们向基类的拷贝构造函数和拷贝赋值运算符传入派生类对象时, 不会发生动态绑定, 使用的是基类的定义

    构造函数构造一个基类对象, 赋值运算符只处理基类成员
1Bulk_quote bulk;
2Quote item(bulk);    // Quote::Quote
3item = bulk;         // Quote::operator=

上述过程会忽略Bulk_quote部分, 所以我们可以说bulk的Bulk_quote部分被切掉 sliced down

当我们用一个派生类对象为一个基类对象初始化或赋值时, 只有派生类对象的基类部分会被拷贝, 移动或赋值, 其派生类部分将被忽略掉


存在继承关系的类型之间的转换规则

  1. 从派生类到基类的类型转换只对指针和引用有效
  2. 不存在基类到派生类的隐式类型转换
    • staic_cast
    • dynamic_cast
  3. 派生类到基类的类型转换可能由于访问受限而不可行

    要求派生为public

可以将派生类对象拷贝, 移动或赋值给一个基类对象


类型转换与继承


我们可以使基类的指针和引用指向/绑定到派生类对象

使用基类的指针和引用时, 我们并不清楚对象的真实类型

智能指针也支持派生类向基类的类型转换


静态类型与动态类型

当我们使用存在继承关系的类型时, 需区分静态类型 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, 强制覆盖编译器的检查工作


对象之间不存在类型转换

派生类向基类的自动类型转换只对指针或引用类型有效, 在派生类类型和基类类型之间不存在这样的转换


接受引用的拷贝构造函数和拷贝赋值运算符

  1. 拷贝构造函数和拷贝赋值运算符通常只包含一个参数, 具有底层const的类类型引用
  2. 构造函数是不能作为虚函数的, 拷贝赋值运算符通常不会被定义为虚函数
  3. 当我们向基类的拷贝构造函数和拷贝赋值运算符传入派生类对象时, 不会发生动态绑定, 使用的是基类的定义

    构造函数构造一个基类对象, 赋值运算符只处理基类成员
1Bulk_quote bulk;
2Quote item(bulk);    // Quote::Quote
3item = bulk;         // Quote::operator=

上述过程会忽略Bulk_quote部分, 所以我们可以说bulk的Bulk_quote部分被切掉 sliced down

当我们用一个派生类对象为一个基类对象初始化或赋值时, 只有派生类对象的基类部分会被拷贝, 移动或赋值, 其派生类部分将被忽略掉


存在继承关系的类型之间的转换规则

  1. 从派生类到基类的类型转换只对指针和引用有效
  2. 不存在基类到派生类的隐式类型转换
    • staic_cast
    • dynamic_cast
  3. 派生类到基类的类型转换可能由于访问受限而不可行

    要求派生为public

可以将派生类对象拷贝, 移动或赋值给一个基类对象