C++学习笔记----9、发现继承的技巧(七)---- 转换(2)
3、dynamic_cast()
dynamic_cast()在继承层次结构内进行转换时提供了运行时检查。可以使用它来转换指针或引用。dynamic_cast()在运行时检查相关对象运行时的类型信息。如果转换讲不通,dynamic_cast()返回一个null指针(对于指针转换),或者抛出std::bad_cast例外(对于引用转换)。
例如,假定有下面的类层次结构:
class Base
{
public:
virtual ~Base() = default;
};
class Derived : public Base
{
public:
virtual ~Derived() = default;
};
下面的例子展示dynamic_cast()的正确使用:
Base* b;
Derived* d{ new Derived{} };
b = d;
d = dynamic_cast<Derived*>(b);
下面引用上使用dynamic_cast()会产生一个例外抛出:
Base base;
Derived derived;
Base& br{ base };
try {
Derived& dr{ dynamic_cast<Derived&>(br) };
} catch (const bad_cast&) {
println("Bad cast!");
}
注意可以用static_cast()或reinterpret_cast()来执行同样的继承层次结构的向下转换。不同的是dynamic_cast()执行运行时(动态)类型检查,而static_cast()与reinterpret_cast()执行转换,即使它们是错误的。
记住,运行时类型信息被保存在对象的vtable中。因此,为了使用dynamic_cast(),类至少要有一个virtual成员函数。如果类没有vtable,尝试使用dynamic_cast()会产生编译错误。例如微软Visual C++会给出如下错误:
error C2683: 'dynamic_cast' : 'Base' is not a polymorphic type.
4、std::bit_cast()
std::bit_cast()定义在<bit>中。它是标准库中唯一的一个转换;其它的转换是c++语言本身的一部分。bit_cast()与reinterpret_cast()类似,但是它生成了一个给定目标类型的新对象,从源对象中按位拷贝到新的对象。它高效地解释了源对象中的位,就像它们是目标对象的位一样。bit_cast()要求源对象与目标对象大小相同,并且是trivially copyable。
注意:trivially copyable类型是一种其背后的字节组成的对象可以拷贝到一个数组中,例如,char。如果数组中的数据拷贝回对象的话,对象保持原来的值。
下面是一个例子:
float asFloat{ 1.23f };
auto asUint{ bit_cast<unsigned int>(asFloat) };
if (bit_cast<float>(asUint) == asFloat) { println("Roundtrip success."); }
bit_cast()的使用场景是trivially copyable类型的进制I/O。例如,可以将这种类型的每个字节写到文件中。当从文件中读取到内存时,可以使用bit_cast()正确解释来自文件的字节。
5、转换总结
下面的表总结了应用于不同情的转换。
情形 | 转换 |
去除常量特性 | const_cast() |
显式进行语言支持的转换(例如,int到double,int到bool) | static_cast() |
显式进行支持用户定义的构造函数或转换的转换 | static_cast() |
将一个类的对象转换为另一个(不相关的)类的对象 | bit_cast() |
相同层次结构的类中一个类的对象指针到另一个类的对象指针 | 推荐dynamic_cast()或static_cast() |
相同层次结构的类中一个类的对象引用到另一个类的对象引用 | 推荐dynamic_cast()或static_cast() |
类型指针到无关的类型指针 | reinterpret_cast() |
类型引用到无关类型引用 | reinterpret_cast() |
函数指针到函数指针 | reinterpret_cast() |