我写C和C++代码已经快二十年了,但这些语言中有一个方面我从未真正理解过。我显然使用了常规的石膏,即。

MyClass *m = (MyClass *)ptr;

到处都是,但似乎有两种其他类型的演员,我不知道有什么不同。以下代码行之间有什么区别?

MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);

当前回答

dynamiccast具有运行时类型检查功能,仅适用于引用和指针,而staticcast不提供运行时类型检测。有关完整信息,请参阅MSDN文章static_cast Operator。

其他回答

C样式强制转换合并了const_cast、static_cast和reinterpret_cast。

我希望C++没有C样式转换。C++强制转换非常突出(应该如此;强制转换通常表示做了坏事),并正确区分强制转换执行的不同类型的转换。它们还允许编写类似的函数,例如boost::lexical_cast,从一致性的角度来看,这很不错。

静态铸造

staticcast用于您基本上想要反转隐式转换的情况,但有一些限制和添加。staticcast不执行运行时检查。如果您知道您引用的是特定类型的对象,因此不需要进行检查,则应使用此选项。例子:

void func(void *data) {
  // Conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() {
  MyClass c;
  start_thread(&func, &c)  // func(&c) will be called
      .join();
}

在本例中,您知道您传递了MyClass对象,因此不需要运行时检查来确保这一点。

动态铸造

dynamic_cast在您不知道对象的动态类型时非常有用。如果引用的对象不包含作为基类转换为的类型,则它将返回空指针(在这种情况下,当您转换为引用时,会引发bad_cast异常)。

if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
  ...
}

如果参数类型不是多态的,则不能使用dynamic_cast进行下变频(转换为派生类)。例如,以下代码无效,因为Base不包含任何虚拟函数:

struct Base { };
struct Derived : Base { };
int main() {
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // Invalid
}

“向上转换”(向基类转换)对于static_cast和dynamic_cast始终有效,而且也没有任何转换,因为“向上”是隐式转换(假设基类是可访问的,即它是公共继承)。

常规铸造

这些造型也称为C型造型。C风格的强制转换基本上与尝试一系列C++强制转换序列相同,并采用第一个有效的C++强制转换,而不考虑dynamic_cast。不用说,这是更强大的,因为它结合了const_cast、static_cast和reinterpret_cast,但它也不安全,因为它不使用dynamic_cast。

此外,C样式转换不仅允许您这样做,而且还允许您安全地转换到私有基类,而“等效”的static_cast序列会给您带来编译时错误。

有些人更喜欢C风格的演员,因为他们简洁。我只将它们用于数字强制转换,当涉及用户定义的类型时,使用适当的C++强制转换,因为它们提供了更严格的检查。

仅供参考,我相信Bjarne Stroustrup曾说过,应该避免C风格的强制转换,如果可能的话,应该使用static_cast或dynamic_cast。

Barne Stroustrup的C++风格常见问题解答

你愿意接受那个建议吗。我远非C++大师。

dynamiccast具有运行时类型检查功能,仅适用于引用和指针,而staticcast不提供运行时类型检测。有关完整信息,请参阅MSDN文章static_cast Operator。

避免使用C样式转换。

C样式转换是常量转换和重新解释转换的混合,很难在代码中找到和替换。C++应用程序程序员应该避免C样式转换。