类型转换运算符有特定的语法:它以 operator 关键字开头,后跟目标类型和一对空括号。目标类型是返回类型,因此在 operator 关键字之前不指定。在本教程中,我们将了解 C++ 中如何通过转换运算符进行转换。转换运算符是一个一元运算符,它将一种数据类型转换为另一种数据类型。
C++ 中的转换运算符支持四种类型的转换,它们是:
这是最基本的类型转换。它是一种编译时转换。它执行隐式类型转换(例如 int 到 float 或指针到 void*),也可以调用显式转换函数(或隐式函数)。
static_cast 可以转换指向相关类的指针,不仅包括向上转型(从派生类指针到基类指针),还包括向下转型(从基类指针到派生类指针)。在运行时,不会执行检查以确保被转换的对象是目标类型的完整对象。因此,程序员有责任确保转换是安全的。另一方面,它不会产生 dynamic_cast 类型安全检查的开销。
语法
class Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * b = static_cast<Derived*>(a);
即使 b 将指向一个不完整的类对象,如果解除引用可能会导致运行时错误,但这仍然是有效的代码。
因此,static_cast 不仅可以执行隐式允许的转换,还可以通过指向类的指针执行它们的逆转换。
Static_cast 还可以执行所有隐式转换(不仅仅是那些涉及指向类的指针的转换),以及这些转换的逆转换。
这可以将 void* 转换为任何指针类型。在这种情况下,如果 void* 值是通过从相同指针类型转换而来的,则它确保生成的指针值是相同的。整数、浮点值和枚举类型都可以转换为枚举类型。
例如
#include <iostream> using namespace std; int main() { float f = 4.6; int a = f; int b = static_cast<int>(f); cout << b; }
输出
4
只有指向类的指针和引用,或 void*,才能使用 dynamic_cast。其目标是确保类型转换结果指向目标指针类型的有效完整对象。
这自然包括指针向上转型(从派生类指针到基类指针),与允许隐式转换的方式相同。
然而,dynamic_cast 可以向下转型(它可以从基类指针转换为派生类指针)多态类(那些具有虚成员的类),但这只发生在被指向的对象是目标类型的有效完整对象的情况下。
例如:
#include <iostream>
#include <exception>
using namespace std;
class Base { virtual void dummy() {} };
class Derived: public Base { int a; };
int main () {
try {
Base * pba = new Derived;
Base * pbb = new Base;
Derived * pd;
pd = dynamic_cast<Derived*>(pba);
if (pd==0) cout << "Null pointer is on the first type-cast.\n";
pd = dynamic_cast<Derived*>(pbb);
if (pd==0) cout << "Null pointer is on the second type-cast.\n";
} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}
输出
Null pointer is on the second type-cast.
上面的代码尝试对 Base* 类型(pba 和 pbb)的指针对象执行两次 dynamic_cast 到 Derived* 类型的指针对象,但只有第一次成功。请注意它们的初始化:
Base * pba = new Derived;
Base * pbb = new Base;
尽管它们都指向 Base* 类型的对象,但 pba 实际上指向一个 Derived 对象,而 pbb 指向一个 Base 对象。因此,当使用 dynamic_cast 执行各自的类型转换时,pba 指向一个完全形成的 Derived 类对象,而 pbb 指向一个仅部分形成的 Base 类对象。
当 dynamic_cast 无法转换指针因为它不是所需类的完整对象时(如上例中的第二次转换),它会返回一个空指针以指示失败。如果 dynamic_cast 用于转换为引用类型并且转换失败,则会抛出 bad_cast 异常。
其他允许的指针隐式转换有:在指针类型之间(即使在不相关的类之间)转换空指针,以及将任何类型的任何种类指针主要转换为 void* 指针。
这种类型转换操作指针指向对象的常量性,无论是设置还是移除它。用于将 const 指针传递给期望非 const 参数的函数。
// const_cast
#include <iostream>
using namespace std;
void print (char * str)
{
cout << str << '\n';
}
int main () {
const char * c = "just a sample text";
print ( const_cast<char *> (c) );
return 0;
}
输出
just a sample text
在上述示例中,仅因为函数 print 实际上没有写入所指向的对象,所以才能保证其工作。应该注意的是,为了写入所指向的对象而移除其常量性会导致未定义的行为。
reinterpret_cast 将任何指针类型转换为任何其他指针类型,即使它们来自不同的类。该操作会简单地将一个指针的值从二进制复制到另一个指针。
它还能够将指针转换为整数类型,反之亦然。这个整数值以平台特定的格式表示一个指针。唯一的保证是,将一个指针转换为足够大的整数类型(例如 intptr_t)以完全包含它后,可以将其转换回有效的指针。
reinterpret_cast 可以执行但 static_cast 不能执行的转换是低级操作,它们依赖于重新解释类型的二进制表示,从而生成在大多数情况下特定于系统且不可移植的代码。
例如:
class A { /* ... */ };
class B { /* ... */ };
A * a = new A;
B * b = reinterpret_cast<B*>(a);
这段代码可以编译,但没有意义,因为 b 现在指向一个完全不相关且可能不兼容的类对象。解引用 b 绝不安全。