c++ - 运行时多态性和 dynamic_cast 需要澄清
问题描述
可能会在其他地方回答一些问题,但找不到正确的短语来提问
所以听到它去。
我有基类A
,有孩子B
和C
;(完全用于培训目的)
#include <iostream>
class A
{
public:
virtual void print () { std::cout<< "A::print()" << std::endl; }
};
class B: public A
{
public:
void print () { std::cout<< "B::print()" << std::endl; }
};
class C : public B
{
public:
void print () { std::cout<< "C::print()" << std::endl; }
};
所以,在我的主要声明中,我已经声明了基指针A*
bptr;后来孩子的B
也C
宣布了。
后来 bPtr 指向B
并调用print
的函数按预期工作;后来 bPtr 指向C
并调用print
的函数按预期工作;
听到是代码,没有问题听到。
int main()
{
A* bPtr;
B b;
C c;
bPtr = &b;
bPtr->print(); // prints B::print() - as expected;
bPtr = &c;
bPtr->print(); // prints C::print() - as expected;
}
听到是我的困境,我可能理解错了;现在我这些天的想法,dynamic_cast
也完全在上面;但情况有所不同,或者我做错了什么。
int main()
{
A* bPtr = new C;
bPtr = dynamic_cast<B*>( bPtr );
bPtr->print(); // prints C::print() - expected B::print()
/*
I know above can be correct with explicit call
*/
(dynamic_cast<B*>( bPtr ))->B::print(); // B::print
bPtr = dynamic_cast<C*>( bPtr );
bPtr->print(); // prints C::print()
return 0;
if ( B* b = dynamic_cast<B*>( bPtr ))
{
b->print(); // still calls C::print() anyway;
}
}
所以听到我的问题是dynamic_cast
有好处的,并且只有像if
声明这样的地方才能确定基础和孩子之间是否存在继承或基础和孩子之间是否存在安全转换?
if ( B* b = dynamic_cast<B*>( bPtr ))
{
b->print(); // still calls C::print() anyway;
}
解决方案
此行为与 dynamic_cast 无关。
虚拟调用的行为将始终取决于值的实际运行时类型。在您的第二个示例中,唯一实际构造的是 a C
,因此所有调用都将解析为 C,无论您将其称为 A:A * a = bPtr
还是 B: B * b = bPtr
,它都会解析为 C::print() ,因为该语句new C
构造了实际值作为一个 C。
Dynamic_cast 只是将给定的值转换为特定类型,如果它是该类型的(子类型),否则返回nullptr
。因此,动态转换 a B *
toC *
将失败并返回nullptr
,但在您的情况下,您将转换C *
为它的一种基本类型,它将始终成功并且永远不会更改值本身。
推荐阅读
- javascript - 如何验证 vue 中的第一个数字不为零?
- c# - 如何使圆形边框和背景颜色完全适合 TextBlock 中的文本范围?
- mysql - 在 MySQL 中查询同一张表时需要帮助
- vue.js - Vue App中main.js & App.vue的作用是什么
- python-3.x - 如何在python中编写嵌套的switch case?
- c# - 无法使用我的自定义 userControl 保存表单
- excel - 是否可以缩短录制的宏?
- amazon-web-services - 我可以在 S3 中保存 Amazon Lex 日志和指标数据吗?
- asp.net-core - DI注册服务类型.net core 3.0
- jenkins - 从脚本返回的值未分配给在 jenkins 声明性管道阶段声明的变量