经常转换与static_cast vs. dynamic_cast

我已经写了C和C ++代码近二十年了,但是这些语言的一个方面我从来没有真正理解。 我显然使用了常规演员,即

MyClass *m = (MyClass *)ptr; 

到处都是,但似乎还有两种types的演员,我不知道区别。 以下几行代码有什么区别?

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

的static_cast

static_cast用于基本上想要反转隐式转换的情况,只有一些限制和附加。 static_cast执行运行时检查。 如果你知道你指的是一个特定types的对象,那么这个应该被使用,因此检查是不必要的。 例:

 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

当你不知道对象的dynamictypes是什么时, dynamic_cast是有用的。 如果引用的对象不包含作为基类转换的types(当您转换为引用时,在此情况下引发bad_castexception),它将返回空指针。

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

如果向下转换(转换为派生类)并且参数types不是多态,则不能使用dynamic_cast 。 例如,以下代码无效,因为Base不包含任何虚函数:

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

“向上”( static_cast转换为基类)对于static_castdynamic_cast都是有效的,并且也没有任何static_cast转换,因为“向上转换”是隐式转换。

定期演员

这些演员也被称为C型演员。 C风格的转换基本上与尝试一系列C ++转换序列相同,并且可以在不考虑dynamic_cast情况下采用第一个可以工作的C ++转换。 毋庸置疑,这是更强大,因为它结合了const_caststatic_castreinterpret_cast ,但它也是不安全的,因为它不使用dynamic_cast

另外,C风格的转换不仅允许你这样做,而且还允许你安全地转换到一个私有的基类,而“等效的” static_cast序列会给你一个编译时错误。

有些人更喜欢C风格的演员,因为他们简洁。 我只使用它们进行数字转换,并在涉及用户定义types时使用适当的C ++types转换,因为它们提供更严格的检查。

静态投射

静态转换执行兼容types之间的转换。 它类似于C风格的演员,但更具限制性。 例如,C风格的转换将允许一个整数指针指向一个字符。

 char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes 

由于这将导致指向分配内存的1个字节的4字节指针,写入该指针将导致运行时错误或将覆盖一些相邻的内存。

 *p = 5; // run-time error: stack corruption 

与C风格的转换相比,静态转换将允许编译器检查指针和指针数据types是否兼容,这允许程序员在编译期间捕获这个不正确的指针分配。

 int *q = static_cast<int*>(&c); // compile-time error 

重新演绎

要强制指针转换,就像C风格转换在后台执行的一样,将使用reinterpret强制转换。

 int *r = reinterpret_cast<int*>(&c); // forced conversion 

该转换处理某些不相关types之间的转换,例如从一个指针types到另一个不兼容的指针types。 它将简单地执行数据的二进制拷贝而不改变基础位模式。 请注意,这种低级操作的结果是系统特定的,因此不便携。 如果不能完全避免,应该谨慎使用。

dynamic投射

这个仅用于将对象指针和对象引用转换为inheritance层次结构中的其他指针或引用types。 这是通过执行运行时检查指针指向目标types的完整对象来确保指向的对象可以被转换的唯一转换。 对于这个运行时检查是可能的,对象必须是多态的。 也就是说,这个类必须定义或inheritance至less一个虚函数。 这是因为编译器只会为这些对象生成所需的运行时types信息。

dynamic演员的例子

在下面的例子中,MyChild指针使用dynamic转换转换为MyBase指针。 此派生到基础的转换成功,因为子对象包含完整的基础对象。

 class MyBase { public: virtual void test() {} }; class MyChild : public MyBase {}; int main() { MyChild *child = new MyChild(); MyBase *base = dynamic_cast<MyBase*>(child); // ok } 

下一个示例尝试将MyBase指针转换为MyChild指针。 由于Base对象不包含完整的Child对象,因此该指针转换将失败。 为了表明这一点,dynamic强制转换返回一个空指针。 这提供了一个方便的方法来检查转换在运行时是否成功。

 MyBase *base = new MyBase(); MyChild *child = dynamic_cast<MyChild*>(base); if (child == 0) std::cout << "Null pointer returned"; 

如果引用被转换而不是指针,那么dynamic转换将通过抛出bad_castexception而失败。 这需要使用try-catch语句来处理。

 #include <exception> // … try { MyChild &child = dynamic_cast<MyChild&>(*base); } catch(std::bad_cast &e) { std::cout << e.what(); // bad dynamic_cast } 

dynamic或静态演员

使用dynamic转换的优点是它允许程序员在运行时检查转换是否成功。 缺点是执行这个检查有一个性能开销。 由于这个原因,在第一个例子中使用静态转换会更好,因为派生到基地的转换永远不会失败。

 MyBase *base = static_cast<MyBase*>(child); // ok 

但是,在第二个示例中,转换可能成功或失败。 如果MyBase对象包含一个MyBase实例,它将失败,如果它包含一个MyChild实例,它将成功。 在某些情况下,这可能直到运行时才能知道。 在这种情况下,dynamic投射是比静态投射更好的select。

 // Succeeds for a MyChild object MyChild *child = dynamic_cast<MyChild*>(base); 

如果使用静态转换而不是dynamic转换来执行基于派生的转换,则转换不会失败。 它会返回一个指向一个不完整的对象的指针。 解引用这样一个指针可能会导致运行时错误。

 // Allowed, but invalid MyChild *child = static_cast<MyChild*>(base); // Incomplete MyChild object dereferenced (*child); 

Const施放

这个主要用来添加或删除一个variables的const修饰符。

 const int myConst = 5; int *nonConst = const_cast<int*>(&myConst); // removes const 

尽pipeconst转换允许改变常量的值,但这样做仍然是无效的代码,可能会导致运行时错误。 例如,如果该常量位于只读存储器的一部分中,则可能发生这种情况。

 *nonConst = 10; // potential run-time error 

当一个函数接受一个非常量的指针参数,即使它没有修改指针时,const cast也会被使用。

 void print(int *p) { std::cout << *p; } 

然后该函数可以通过使用const转换传递一个常量variables。

 print(&myConst); // error: cannot convert // const int* to int* print(nonConst); // allowed 

来源和更多的解释

你应该看看文章C ++编程/types铸造

它包含了所有不同types转换的很好的描述。 以下取自以上链接:

const_cast会

const_cast(expression)const_cast <>()用于添加/删除variables的const(ness)(或volatile)。

的static_cast

static_cast(expression)static_cast <>()用于在整数types之间进行转换。 '如'char-> long,int-> short等

静态转换也用于投射相关types的指针,例如将void *转换为适当的types。

的dynamic_cast

dynamic转换用于在运行时转换指针和引用,通常用于在inheritance链(inheritance层次结构)上向下或向下转换指针或引用。

dynamic_cast的(expression)

目标types必须是指针或引用types,expression式必须计算为指针或引用。 dynamic转换只在expression式引用的对象的types与目标types兼容且基类至less有一个虚拟成员函数时才起作用。 如果不是,并且被转换的expression式的types是一个指针,则返回NULL,如果引用上的dynamic转换失败,则引发bad_castexception。 当它不失败时,dynamic强制转换将目标types的指针或引用返回到expression式引用的对象。

reinterpret_cast的

重新演绎投射简单地将一种types逐位投射到另一种types。 任何指针或整数types都可以通过重新解释来铸造,容易被滥用。 例如,通过重新解释强制转换,可以不安全地将一个整型指针转换为一个string指针。

避免使用C风格的演员。

C风格的转换是const和reinterpret转换的混合,在代码中很难find和replace。 一个C ++应用程序员应该避免C风格的转换。

仅供参考,我相信Bjarne Stroustrup被引用说,C风格的演员是应该避免的,你应该尽可能使用static_cast或dynamic_cast。

Barne Stroustrup的C ++风格FAQ

听取你的build议。 我远不是一个C ++大师。

C风格强制转换const_cast,static_cast和reinterpret_cast。

我希望C ++没有C风格的演员。 C ++强制转换(正如他们应该这样;转换通常表示正在做一些不好的事情),并恰当地区分转换执行的不同types的转换。 他们还允许编写类似外观的函数,例如boost :: lexical_cast,从一致性angular度来看这是相当不错的。

dynamic_cast具有运行时types检查function,仅适用于引用和指针,而static_cast不提供运行时types检查。 有关完整信息,请参阅MSDN文章static_cast运算符

dynamic_cast只支持指针和引用types。 如果types是一个指针,那么它将返回NULL ,如果该types是一个指针,则不可能抛出exception,否则返回一个exception。 因此,可以使用dynamic_cast来检查一个对象是否是给定的types, static_cast不能(你最终会得到一个无效的值)。

其他答案已经涵盖了C式(和其他)演员。