c++ primer 是否在使用 `dynamic_cast` 时出错了?
Is the c++ primer making something wrong with the usage of `dynamic_cast`?
引自 C++ 入门第 5 期 19.2.1。 dynamic_cast 运算符
A dynamic_cast has the following form:
dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)
where type must be a class type and (ordinarily) names a class that has virtual
functions. In the first case, e
must be a valid pointer (§ 2.3.2, p. 52); in the second, e
must be an lvalue; and in the third, e
must not be an lvalue.
In all cases,the type of e
must be either a class type that is publicly derived from
the target type, a public base class of the target type, or the same as the target
type. If e
has one of these types, then the cast will succeed. Otherwise, the cast fails.
If a dynamic_cast to a pointer type fails, the result is 0. If a dynamic_cast to a
reference type fails, the operator throws an exception of type bad_cast
不过,我在这里写了一段代码:
struct A {};
struct B : private A // note: *private* inheritance
{
A* test() {
return dynamic_cast<A*>(this);
}
};
int main()
{
B b;
if(b.test()==nullptr)
throw 1;
}
在上面的代码片段中,A
只是B
的私有基,c++入门没有考虑到。但是,此代码片段可以编译并且 运行 没有错误。是不是引子搞错了?
总的来说,这是引物部分的一个不幸的措辞。它将人们可以做的两种类型的演员组合成一个句子,然后结果说错了。
转换为基础 class,不需要运行时转换操作。 ,它是一个纯粹的静态结构。并且喜欢T.C。引用,它需要一个 accessbile 基础,而不是 public 基础。所以你的代码一切都很好。
对于运行时强制转换(向下强制转换),C++ 标准对动态强制转换中涉及的操作数和类型提出了要求,以使其成功。 class 必须是 publicly 派生的,否则实现没有义务在继承链中成功转换。我的意思是,理论上它可以使转换成功,但根据规范 "the runtime check fails",这不会留下太多余地。
但无论哪种方式,您的程序都没有导致编译失败的问题,也没有任何问题会导致任何类型的运行时错误。
如果我们将您的代码更改为向下转换而不是向上转换,这里是 example that doesn't even build:
struct A {};
struct B : private A // note: *private* inheritance
{
A* test(B* p) {
return dynamic_cast<A*>(p);
}
friend B* foo(A*);
};
B* foo(A* a) {
return dynamic_cast<B*>(a);
}
int main()
{
B b;
*foo(&b);
}
A
是 foo
中 B
的可访问基数,但演员表是 ill-formed.
将入门课程带回课程的最小改动是将 "a class type that is publicly derived from the target type" 变为 "a class type that is accessibly derived from the target type" .由于 publicly available errata 中没有此类内容,我们可以猜测这是一个尚未指出的编辑错误。
A derived-to-base dynamic_cast
是静态的,而不是动态的,并且只需要在强制转换的上下文中可以访问基础(并且明确)。参见 [expr.dynamic.cast]/5。
加粗的段落明显都是错误的
处理class类型的动态转换表达式在逻辑上可以细分为两种情况。
type
是 class 类型,它是 e
的 静态确定的 类型的基础 class。在这种情况下 dynamic_cast 或多或少与 static_cast 同义。特别是,type
必须是 e
. 类型的可访问且明确(但不一定 public)基 class
type
是一个 class 类型,它不是 e
的 静态确定 类型的基础 class。在这种情况下,会进行运行时检查。这进一步细分为 downcast 和 crosscast 情况。它们之间的差异仅在多重继承 and/or non-public 继承的情况下才重要。在这两种情况下,type
必须是 e
的完整对象的某个子对象的类型。
入门书从未说明它是指 e
的静态类型还是动态类型,但无论哪种情况,描述都是完全错误的。为了演员成功,
type
不需要以任何方式与 e
的 static 类型相关
type
必须是 e
的 dynamic 类型的基础 class 或该类型本身(但不是正确的派生 class),还有与可访问性和 non-ambiguity. 相关的进一步限制
引自 C++ 入门第 5 期 19.2.1。 dynamic_cast 运算符
A dynamic_cast has the following form:
dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)
where type must be a class type and (ordinarily) names a class that has virtual functions. In the first case,
e
must be a valid pointer (§ 2.3.2, p. 52); in the second,e
must be an lvalue; and in the third,e
must not be an lvalue.In all cases,the type of
e
must be either a class type that is publicly derived from the target type, a public base class of the target type, or the same as the target type. Ife
has one of these types, then the cast will succeed. Otherwise, the cast fails.
If a dynamic_cast to a pointer type fails, the result is 0. If a dynamic_cast to a reference type fails, the operator throws an exception of typebad_cast
不过,我在这里写了一段代码:
struct A {};
struct B : private A // note: *private* inheritance
{
A* test() {
return dynamic_cast<A*>(this);
}
};
int main()
{
B b;
if(b.test()==nullptr)
throw 1;
}
在上面的代码片段中,A
只是B
的私有基,c++入门没有考虑到。但是,此代码片段可以编译并且 运行 没有错误。是不是引子搞错了?
总的来说,这是引物部分的一个不幸的措辞。它将人们可以做的两种类型的演员组合成一个句子,然后结果说错了。
转换为基础 class,不需要运行时转换操作。
对于运行时强制转换(向下强制转换),C++ 标准对动态强制转换中涉及的操作数和类型提出了要求,以使其成功。 class 必须是 publicly 派生的,否则实现没有义务在继承链中成功转换。我的意思是,理论上它可以使转换成功,但根据规范 "the runtime check fails",这不会留下太多余地。
但无论哪种方式,您的程序都没有导致编译失败的问题,也没有任何问题会导致任何类型的运行时错误。
如果我们将您的代码更改为向下转换而不是向上转换,这里是 example that doesn't even build:
struct A {};
struct B : private A // note: *private* inheritance
{
A* test(B* p) {
return dynamic_cast<A*>(p);
}
friend B* foo(A*);
};
B* foo(A* a) {
return dynamic_cast<B*>(a);
}
int main()
{
B b;
*foo(&b);
}
A
是 foo
中 B
的可访问基数,但演员表是 ill-formed.
将入门课程带回课程的最小改动是将 "a class type that is publicly derived from the target type" 变为 "a class type that is accessibly derived from the target type" .由于 publicly available errata 中没有此类内容,我们可以猜测这是一个尚未指出的编辑错误。
A derived-to-base dynamic_cast
是静态的,而不是动态的,并且只需要在强制转换的上下文中可以访问基础(并且明确)。参见 [expr.dynamic.cast]/5。
加粗的段落明显都是错误的
处理class类型的动态转换表达式在逻辑上可以细分为两种情况。
type
是 class 类型,它是e
的 静态确定的 类型的基础 class。在这种情况下 dynamic_cast 或多或少与 static_cast 同义。特别是,type
必须是e
. 类型的可访问且明确(但不一定 public)基 class
type
是一个 class 类型,它不是e
的 静态确定 类型的基础 class。在这种情况下,会进行运行时检查。这进一步细分为 downcast 和 crosscast 情况。它们之间的差异仅在多重继承 and/or non-public 继承的情况下才重要。在这两种情况下,type
必须是e
的完整对象的某个子对象的类型。
入门书从未说明它是指 e
的静态类型还是动态类型,但无论哪种情况,描述都是完全错误的。为了演员成功,
type
不需要以任何方式与e
的 static 类型相关type
必须是e
的 dynamic 类型的基础 class 或该类型本身(但不是正确的派生 class),还有与可访问性和 non-ambiguity. 相关的进一步限制