在这里,我不讨论各种cast的使用范围和区别,也没有考虑汇编在类型转换间的应用。
一、类型转换本质
在C++中,所有数据都是“类”的实例,所有实例在计算机看来不过是内存中的一堆二进制码而已。
1110100011100110110000101100011 代表什么?为了方便讨论,将其转换为十六进制码74 73 61 63
那么“74 73 61 63”代表什么呢?
是数字1953718627(考虑到大小端的问题,也可能是数字1667330932);是 t s a c 四个字母(依照ASCII)。
如图:
当然也可能是其他的我们知道或者不知道的东西,这就要看我们打算如何解释了。
C++的类型转换在本质上:对内存中指定二进制码的解释方式的转换。从这个角度讲,类型转换和不同语言之间的翻译是一样的。
上面列举的例子对应的C++代码
union CAST //联合类型最能体制类型转换的本质
{
struct
{
char c;
char a;
char s;
char t;
} cast;
long num;
};
void main()
{
CAST ct;
ct.cast.c='c';
ct.cast.a='a';
ct.cast.s='s';
ct.cast.t='t';
//打印ct.number
}
二、 父类和子类的类型转换
先简单说下父类和子类的内存空间布局。子类的内存布局是在排布完父类的内存布局后,继续排布自身特有的内存。如图:
上图是单继承下的父类和子类的内存布局示意图。对于多继承,大同小异。(我本人不赞成在编程中使用多继承)。
了解了父类和子类的内存布局后,那么父类和子类之间的类型转换也就很容易理解了:
①将子类转换成父类,则子类的自身成员不会被程序解释(也就是不会被程序使用),剩下的成员和父类成员内存布局完全相同,也就是按照父类方式解释。这也就是子类可以在父类出现的地方替换父类、扮演父类角色的原因。
②将父类转换成子类,因为子类可能有父类没有的成员,所以子类的内存布局就可能和父类不同,父类也就有可能实现不了子类的某些功能。但是,如果父类转换成子类、同时不去使用子类的特有成员呢?或者父类成员和子类成员完成相同呢?
三、友元方面的应用
我们知道,C++中如果要在类外部修改类的成员,有几种情况的可行:
①类成员是公开(public)
②类自身提供修改接口(函数)
③类的友元
④在子类中修改
那么有没有可能使用类型转换修改呢?答案是有可能。
就是利用类型转换的本质,强行暴露类的成员,实现类的友元。示例代码如下:
class A
{
private:
int m;
int n;
public:
A()
{
m=0;
n=0;
}
void print()
{
//打印 m,n
}
};
class B
{
public:
int m; //用于暴露A的成员m
int n; //用于暴露A的成员n
};
void main()
{
A *a=new A;
a->print();
B *b=(B*)a; //类型转换
b->m=1;
b->n=1;
a->print();
}
总之,类型转换的本质上是对内存的解释的转换;类型转换是否成功,主要取决于这一类型的内存空间是否能成功解释成哪一类型的内存布局。由此引申出的应用可以在恰当的环境中使用,也许会收到意想不到的结果。