检查交叉投射是否可行?
我知道使用 dynamic_cast
在类层次结构中进行“交叉转换”是合法的。例如,如果我有如下所示的类:
A B
\ /
C
如果我有一个指向 C
类型的对象的 A*
指针,那么我可以使用它
A* aPtr = /* ... something that produces a C* ... */
B* bPtr = dynamic_cast<B*>(aPtr);
来获取指针到我指向的 C
的 B
基础对象。
我提到这一点的原因是,在我编写上面的代码时,编译器可能还没有看到 C
的定义,尽管它已经看到了 A
和B
。这意味着编译器可能不会检测到 A
和 B
之间的任何类型的连接,但它仍然必须编译代码,因为对于像这样的类是可能的C
存在并让 dynamic_cast
在某些情况下成功。
问题是,这意味着我可能会意外地交叉转换到错误类型的对象。假设我有如下所示的类:
A B D
\ /
C
这里,D
是一些随机的不相关的类。如果我尝试编写这样的内容:
A* aPtr = /* ... get a C* pointer ... */
D* dPtr = dynamic_cast<D*>(aPtr);
那么这个 dynamic_cast
在运行时总是会失败,因为没有可能的方法来连接 A
和 D
。如果我因为想使用 B
而意外使用了 D
,编译器将不会给我任何指示,表明我进行了无意义的强制转换。
我的问题是:是否有某种方法可以让编译器警告我转换在运行时总是会失败?我很乐意提供语言级解决方案或任何编译器设置可以检测到这一点的主要编译器。如果有外部工具也没关系;我只是想知道是否有可能捕获此类错误。
I know that it's legal to use dynamic_cast
to do a "cross-cast" across a class hierarchy. For example, if I have classes that look like this:
A B
\ /
C
If I have an A*
pointer that's pointing at an object of type C
, then I can use
A* aPtr = /* ... something that produces a C* ... */
B* bPtr = dynamic_cast<B*>(aPtr);
to get a pointer to the B
base object of the C
I'm pointing at.
The reason I mention this is that at the time that I write the above code, it's possible that the compiler has not yet seen the definition of C
even though it's seen A
and B
. This means that it's possible that the compiler does not detect any sort of connection between A
and B
, but it still has to compile the code anyway because it's possible for a class like C
to exist and for the dynamic_cast
to succeed under some circumstance.
The problem is that this means that I can accidentally cross-cast to an object of the wrong type. Suppose that I have classes that look like this:
A B D
\ /
C
Here, D
is some random unrelated class. If I try writing something like this:
A* aPtr = /* ... get a C* pointer ... */
D* dPtr = dynamic_cast<D*>(aPtr);
Then this dynamic_cast
will always fail at runtime, since there's no possible way to connect A
and D
. If I'm using D
accidentally because I meant to use B
, the compiler will give me no indication whatsoever that I have a meaningless cast.
My question is: is there some way that I can get the compiler to warn me that the cast will always fail at runtime? I'd be happy with a language-level solution or some compiler setting for any major compiler that could detect this. If there's an external tool, that's fine as well; I just want to know if it's possible to catch this class of errors.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在编译时不可能检测到这一点。引入这种关系的类
C
可以在尚未编写的动态可加载库中找到,并且编译器无法证明其他情况。但可能也有一些例外。如果
A
仅具有私有构造函数(或私有析构函数),则编译器可以确定不存在未被A
命名为友元的新子类。It's not possible to detect this at compile-time. The class
C
that introduces the relationship could be found in a dynamically loadable library that hasn't even been written yet, and the compiler can't prove otherwise.There may be a few exceptions though. If
A
has only private constructors (or a private destructor) then the compiler can be certain that there will be no new subclasses that aren't named as friends byA
.这就是动态转换的全部含义:它是动态的,即它是在运行时而不是编译时检查的。
编译器仅检查强制转换的类是否是多态的。如果类不是多态的,那么将没有足够的信息来检查运行时的转换。
最后,在动态转换之后,程序应该检查接收到的指针是否不为空。如果您转换为引用,那么您应该捕获 std::bad_cast。
That's the whole meaning of the dynamic cast: It is dynamic i.e. it is checked at the runtime not at the compilation time.
The compiler only checks if the casted classes are polymorphic. If the classes are not polymorphic then there will not be enough information to check the casting at the runtime.
And finally after the dynamic cast the program should check if the received pointer is not null. If you cast to a reference then you should catch std::bad_cast.
事实上,当您使用
dynamic_cast
时,即使类彼此无关,您也可以将任何多态类型指针强制转换为任何多态类型指针。如果您想要编译时检查,则需要使用其他强制转换 -
static_cast
或隐式转换 - 在许多情况下,由于某些其他原因可能不适合。当需要
dynamic_cast
时,我们使用的解决方案是一个模板化函数,它执行dynamic_cast
并在获得空指针时抛出异常。这当然只是运行时检查,但相当可靠。Truth is when you use
dynamic_cast
you can cast any polymorphic type pointer to any polymorphic type pointer even when classes are unrelated to each other.If you want compile-time check you need to use other casts -
static_cast
or implicit conversions - that might not suit for some other reasons in many cases.The solution we use when
dynamic_cast
is needed is a templated function that doesdynamic_cast
and throws an exception if a null pointer is obtained. That's of course a runtime check only, but it's rather reliable.