一个VC编译错误引发的对显示类型转换的思考(static_cast、dynamic_cast和const_cast)(三)
n转换为type-id类型,但没有运行时类型检查来保证转换的安全性。做这些转换前,你必须确定要转换的数据确实是目标类型的数据,因为static_cast不做运行时的类型检查以保证转换的安全性。也因此,static_cast不如dynamic_cast安全。对含有二义性的指针,dynamic_cast会转换失败,而static_cast却直接且粗暴地进行转换。这是非常危险的。
使用场景:
a、用于类层次结构中基类和子类之间指针或引用的转换。
进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的。
b、用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
c、把void指针转换成目标类型的指针(不安全!!)
d、把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。
举例:
a、用于类层次结构中基类和子类之间指针或引用的转换。
[cpp]
// CastExample.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
using namespace std;
class Point
{
protected:
int m_x,m_y;
public:
Point()
{
m_x = 0;
m_y = 0;
}
Point(int x, int y)
{
m_x = x;
m_y = y;
}
void print()
{
cout<
}
};
class Point3d : public Point
{
private:
int m_z;
public:
Point3d(int x, int y, int z):Point(x, y),m_z(z){}
void print()
{
cout<
}
};
void f(Point* p1, Point3d* p2)
{
Point* pa = static_cast(p2); //safe
Point3d* pb = static_cast(p1);//unsafe
pa->print();
pb->print();
}
int main()
{
Point p(1, 2);
Point3d p3d(1, 2, 3);
f(&p, &p3d);
return 0;
}
运行结果为:
虽然编译能够通过,但是运行出的结果很明显是不正确的!
Point* pa = static_cast(p2); 是将子类类型对象转为父类类型对象,因为父类对象的数据成员子类都可以提供,所以没有问题。
Point3d* pb = static_cast
(p1); 是将父类类型对象转为子类类型对象,因为子类对象的数据成员包括了父类没有的数据成员,所以会造成子类某些数据成员无法赋值,出现“随机值”,出现了问题。
b、在两个类对象之间进行转换,比如把类型为A的对象a,转换为类型为B的对象。如下:
[cpp]
#include "stdafx.h"
#include
#include
using namespace std;
class Student
{
public:
string name;
int age;
string sno;
public:
Student(string name = "", int age = 20, string sno = ""):name(name),age(age),sno(sno){}
void print()
{
cout<<"name = "<
Teacher(const Student& stu)
{
name = stu.name;
age = stu.age;
tno = stu.sno;
}
void print()
{
cout<<"name = "<
Teacher tea = static_cast(stu);
tea.print();
}
如果让以上代码通过编译,那么Teacher类必须含有以Student类的对象(或对象的引用)为参数的构造函数。即:
[cpp]
Teacher(const Student& stu)
{
name = stu.name;
age = stu.age;
tno = stu.sno;
}
这实际上是把转换的工作交给构造函数去做了。
这是一个很重要的发现,我们来验证一下:
将例a中的代码修改一下,去掉所有的指针,直接使用对象
[cpp]
// CastExample.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
using namespace std;
class Point
{
public:
int m_x,m_y;
public:
Point()
{
m_x = 0;
m_y = 0;
}
Point(int x, int y)
{
m_x = x;
m_y = y;