c++ - 如何正确使用 dynamic_cast 向下转换?
问题描述
我很困惑dynamic_cast
。C++ Primer和cppreference (规则 5)中的材料无法帮助我理解。(cppreference 比这本书要难得多,我都非常仔细地阅读了它们)
从C++ Primer 5th开始:
dynamic_cast<type*>(e)
在所有情况下,类型
e
必须是从目标类型公开派生的类类型、目标类型的public
基类或与目标类型相同。如果e
具有这些类型之一,则演员表将成功...
所以这就是我如何理解上面引用的文字:
(基类有虚函数)
dynamic_cast
成功,如果:
e
是从type
.e
是孩子。上调。e
是一个基类type
?type
是孩子。沮丧。e
与 相同type
。边播?
示例代码:
#include <iostream>
using namespace std;
struct A {
virtual void foo() {}
};
struct B : A {
};
struct C : B {
};
int main()
{
A* pa = new B;
if (C* pc = dynamic_cast<C*>(pa)) {
cout << "1"; //B is a base class of C
}
return 0;
}
我不明白为什么这种沮丧会失败,我认为它满足条件 2.和规则 5)(来自 cppreference)。
如果这本书是错误的(又一次该死),有人会从 cppreference详细说明规则 5)吗?没有例子,我无法完全理解它所说的......
解决方案
这是来自 cppreference 的规则和我的注释:
5) 如果 expression 是指向多态类型 Base 的指针或引用,并且 new_type 是指向 Derived 类型的指针或引用,则执行运行时检查:
这适用。B
是 的基础C
。
a) 检查由表达式指向/标识的最派生对象。如果在该对象中,表达式指向/引用 Derived 的公共基,并且如果只有一个 Derived 类型的子对象是从表达式指向/标识的子对象派生的,则转换的结果指向/引用该 Derived 子对象。(这被称为“沮丧”。)
指向的最衍生对象pa
是类型B
。
虽然B
是 的公共基础,但指向C
的特定实例不是实例的基础子对象的实例。指向的实例是一个“具体”对象。所以,本案不适用。pa
B
C
B
一个例子:
C c;
B* bp = &c; // bp points to base subobject of C
C* cp = dynamic_cast<C*>(bp);
assert(cp);
B b2;
B* bp2 = &b2; // bp does not point to a base subobject
C* cp2 = dynamic_cast<C*>(bp2);
assert(!cp2);
b) 否则,如果表达式指向/引用最派生对象的公共基类,并且同时,最派生对象具有 Derived 类型的明确公共基类,则转换的结果指向/引用派生对象(此被称为“边播”。)
pa
不指向基类为 的最派生对象C
,因此这种情况不适用。
侧投的一个例子:
struct base {
virtual ~base(){}; // for polymorphism
};
struct left : base {};
struct right : base {};
struct derived : left, right {};
derived d;
left* l = &d;
right* r = dynamic_cast<right*>(l);
c)否则,运行时检查失败。如果在指针上使用了 dynamic_cast,则返回 new_type 类型的空指针值。如果它用于引用,则抛出异常 std::bad_cast。
5a 和 5b 的情况都不适用,所以这种“否则”的情况 5c 是适用的。
- e 与类型相同。边播?
不是旁观者。边播在 5b 中解释。转换为相同类型只是一个身份转换(很少有用,因此也不是常用的术语)。
本书尝试的条件可能描述了转换是否格式良好。虽然,“那么演员就会成功”当然似乎意味着更多。引用的规则对于描述强制转换是否在运行时成功是不正确的。
如果整个程序格式正确,则编译器必须编译该程序。如果表达式格式错误,则编译器必须给您一条诊断消息,说明您做错了。
您展示的示例程序格式正确,并且必须成功编译。它确实在我的系统上编译。
推荐阅读
- android - Android模拟器 - 相机错误 - 无法连接到相机
- c# - 在 ASP.NET MVC 中验证发布数据
- jquery - jQuery脚本在到达日期后添加类
- node.js - 防止 webpack 接触环境变量?
- crc - CRC 查表优化是如何工作的?
- c - 访问 C 文件中的汇编宏函数/指令
- github - 在 GitHub 上为发布标记提交的方法是什么?
- node.js - Actions on Google 的登录方法存在问题
- mysql - 选择月份、年份和数量,并显示零条目的月份
- twilio-studio - Twilio Studio - 请求正文的身份验证错误