我对static_cast
感到复杂,因为它是最安全的C ++演员,但允许同时进行安全和不安全的转换,因此您必须知道上下文,以确定它是否真的安全或可能会导致UB(例如,当投射到子类时)。
那么为什么没有更安全的明确演员呢?这是一个例子,它可能是有用的。在COM中,他们必须将接口指针返回为void** ppv
,因此“必须”明确地转换
*ppv = (IInterface*) this;
然后建议用更安全的C ++演员代替
*ppv = static_cast<IInterface*>(this);
但是在这里做一个static_cast
是否有意义? this
是一个派生自IInterface
的类,因此可以简单地编写
IInterface* p = this; // implicit conversion to base, safe for sure
*ppv = p;
或使用像
这样的帮手template<class T, class U>
T implicit_cast(U p) { return p; }
*ppv = implicit_cast<IInterface*>(this);
那么,static_cast
是否有时被滥用并且在某些情况下可以(应该?)被这个implicit_cast
取代,或者我错过了什么?
编辑:我知道a cast is required in COM,但它不一定是static_cast
,隐式演员就足够了。
答案 0 :(得分:5)
在这种特殊情况下,我相信人们总是知道铸造是向上的,因此static_cast
应该是完全安全的。
看来使用implicit_cast
可能会更安全,并且允许您明确选择要隐式转换到哪个基类(这显然是COM所必需的)。
我使用g ++进行了快速测试,而implicit_cast
确实为预期的不同基类返回了不同的地址。
请注意,关于你的第一句话,我认为dynamic_cast
实际上比static_cast
更安全,因为如果无法完成演员,它将返回null或throw。相比之下,static_cast
将返回一个有效的指针,让你继续前进,直到你的程序在未来的某个时间爆炸,与原始的糟糕演员无关。
测试程序:
#include <iostream>
class B1
{
public:
virtual ~B1() {}
};
class B2
{
public:
virtual ~B2() {}
};
class Foo : public B1, public B2
{
};
template<class T, class U>
T implicit_cast(U p) { return p; }
int main()
{
Foo* f = new Foo;
void **ppv = new void*;
*ppv = implicit_cast<B1*>(f);
std::cout << *ppv << std::endl;;
*ppv = implicit_cast<B2*>(f);
std::cout << *ppv << std::endl;;
return 0;
}