2. 动态转换
动态转换(dynamic_cast)是用于含有虚函数的类创建的对象之间的类型转换,主要是用于按继承链安全向下转型转换或跨层级转换。
语法
dynamic_cast<新类型>(表达式)
动态转换 的过程是根据虚表进行判断。
dynamic_cast 是在运行时进行的类型转换,动态转换失败的情况有:
- 在指针转换时,转换失败返回
nullptr。 - 在引用转换时转换失败会抛出
std::bad_cast类型的异常。
示例
// filename: dynamic_cast.cpp
#include <iostream>
#include <exception>
using namespace std;
class Point {
public:
Point(float ax=0, float ay=0):x(ax), y(ay) { }
// 注意以下函数已经改成虚函数
virtual void info(void) {
cout << "点(" << x << "," << y << ")\n";
}
public:
float x;
float y;
};
class Circle : public Point {
public:
Circle(float ax, float ay, float radius)
: Point(ax, ay), r(radius) { }
void info(void) { // 子类的此函数也为虚函数
cout << "圆(" << x << "," << y << "," << r << ")\n";
}
public:
float r; // 半径
};
int main(int argc, char * argv[]) {
Point p1(1, 2);
Circle c1(3, 4, 5);
Point * pp;
Circle *pc;
pp = dynamic_cast<Point*>(&c1);
if (nullptr == pp)
printf("dynamic_cast<Point*>(&c1): 转换失败!\n");
else
pp->info();
pc = dynamic_cast<Circle*>(&p1);
if (nullptr == pc)
printf("dynamic_cast<Circle*>(&p1): 转换失败!\n");
else
pc->info();
try {
Point & rp = dynamic_cast<Point&>(c1);
rp.info();
} catch (std::bad_cast &err) {
printf("dynamic_cast<Point&>(c1): 转换失败!\n");
}
try {
Circle & rc = dynamic_cast<Circle&>(p1);
rc.info(); // 运行结果有错。
} catch (std::bad_cast &err) {
printf("dynamic_cast<Circle&>(p1): 转换失败!\n");
}
return 0;
}
编译和运行结果如下:
weimz@mzstudio:~/old$ g++ -o dynamic_cast dynamic_cast.cpp
dynamic_cast.cpp: In function ‘int main(int, char**)’:
dynamic_cast.cpp:41:10: warning: ‘dynamic_cast<class Circle*>(Point p1)’ can never succeed
41 | pc = dynamic_cast<Circle*>(&p1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
weimz@mzstudio:~/old$ ./dynamic_cast
圆(3,4,5)
dynamic_cast<Circle*>(&p1): 转换失败!
圆(3,4,5)
dynamic_cast<Circle&>(p1): 转换失败!
可见基于有虚函数的类创建的对象进行动态转换时,基类对象转为子类对象的指针或引用时都可能失败,返回空指针(指针)或触发错误(引用)。