静态演员表
静态转换执行兼容类型之间的转换。它类似于 C 风格的演员表,但更具限制性。例如,C 风格的转换将允许一个整数指针指向一个字符。
char c = 10; // 1 byte
int *p = (int*)&c; // 4 bytes
由于这会导致 4 字节指针指向已分配内存的 1 字节,因此写入该指针将导致运行时错误或将覆盖一些相邻的内存。
*p = 5; // run-time error: stack corruption
与 C 风格的转换相比,静态转换将允许编译器检查指针和指针数据类型是否兼容,这允许程序员在编译期间捕获这种不正确的指针分配。
int *q = static_cast<int*>(&c); // compile-time error
重新诠释演员表
为了强制指针转换,就像在后台进行 C 样式转换一样,将使用重新解释转换。
int *r = reinterpret_cast<int*>(&c); // forced conversion
此转换处理某些不相关类型之间的转换,例如从一种指针类型到另一种不兼容的指针类型。它将简单地执行数据的二进制副本,而不改变底层的位模式。请注意,这种低级操作的结果是系统特定的,因此不可移植。如果无法完全避免,则应谨慎使用。
动态演员表
这个仅用于将对象指针和对象引用转换为继承层次结构中的其他指针或引用类型。它是唯一一种通过执行运行时检查指针是否指向目标类型的完整对象来确保可以转换指向的对象的强制转换。为了使这种运行时检查成为可能,对象必须是多态的。也就是说,该类必须定义或继承至少一个虚函数。这是因为编译器只会为这些对象生成所需的运行时类型信息。
动态转换示例
在下面的示例中,使用动态MyChild
转换将指针转换为指针。MyBase
这种派生到基的转换成功,因为 Child 对象包括一个完整的 Base 对象。
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 对象,因此此指针转换将失败。为了表明这一点,动态转换返回一个空指针。这提供了一种在运行时检查转换是否成功的便捷方法。
MyBase *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);
if (child == 0)
std::cout << "Null pointer returned";
如果转换的是引用而不是指针,则动态转换将通过抛出bad_cast
异常而失败。这需要使用try-catch
语句来处理。
#include <exception>
// …
try
{
MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e)
{
std::cout << e.what(); // bad dynamic_cast
}
动态或静态演员表
使用动态转换的优点是它允许程序员在运行时检查转换是否成功。缺点是执行此检查会产生相关的性能开销。出于这个原因,在第一个示例中使用静态转换会更可取,因为派生到基的转换永远不会失败。
MyBase *base = static_cast<MyBase*>(child); // ok
但是,在第二个示例中,转换可能成功也可能失败。MyBase
如果对象包含一个实例,它将失败,如果MyBase
它包含一个实例,它将成功MyChild
。在某些情况下,这可能直到运行时才知道。在这种情况下,动态转换是比静态转换更好的选择。
// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);
如果使用静态转换而不是动态转换执行了从基到派生的转换,则转换不会失败。它会返回一个指向不完整对象的指针。取消引用这样的指针会导致运行时错误。
// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);
// Incomplete MyChild object dereferenced
(*child);
常量演员
这主要用于添加或删除const
变量的修饰符。
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const
尽管const
cast 允许更改常量的值,但这样做仍然是可能导致运行时错误的无效代码。例如,如果常量位于只读内存的一部分中,就会发生这种情况。
*nonConst = 10; // potential run-time error
const
cast 主要用于当有一个函数采用非常量指针参数时,即使它不修改指针。
void print(int *p)
{
std::cout << *p;
}
然后可以使用强制转换为函数传递一个常量变量const
。
print(&myConst); // error: cannot convert
// const int* to int*
print(nonConst); // allowed
来源和更多解释