关
于
强
制
类
型
转换
的
问题
,很多
书
都
讨论过
,写的最
详细
的是
C++
之父的《
C++
的
设计
和演化》。最好的解决方法就是不要使用
C
风
格的
强
制
类
型
转换
,而是使用
标
准
C++
的
类
型
转换
符:
static_cast, dynamic_cast
。
标
准
C++
中有四个
类
型
转换
符:
static_cast
、
dynamic_cast
、
reinterpret_cast
、和
const_cast
。下面
对
它
们
一一
进
行介
绍
。
static_cast
用法:
static_cast
< type-id > ( expression )
该
运算符把
expression
转换为
type-id
类
型,但没有运行
时类
型
检查
来保
证转换
的安全性。
它主要有如下几
种
用法:
·
用于
类层
次
结
构中基
类
和子
类
之
间
指
针
或引用的
转换
。
进
行上行
转换
(把子
类
的指
针
或引用
转换
成基
类
表示)是安全的;
进
行下行
转换
(把基
类
指
针
或引用
转换
成子
类
表示)
时
,由于没有
动态类
型
检查
,所以是不安全的。
·
用于基本数据
类
型之
间
的
转换
,如把
int
转换
成
char
,把
int
转换
成
enum
。
这种转换
的安全性也要
开发
人
员
来保
证
。
·
把空指
针转换
成目
标类
型的空指
针
。
·
把任何
类
型的表达式
转换
成
void
类
型。
注意:
static_cast
不能
转换
掉
expression
的
const
、
volitale
、或者
__unaligned
属性。
dynamic_cast
用法:
dynamic_cast
< type-id > ( expression )
该
运算符把
expression
转换
成
type-id
类
型的
对
象。
Type-id
必
须
是
类
的指
针
、
类
的引用或者
void *
;如果
type-id
是
类
指
针类
型,那
么
expression
也必
须
是一个指
针
,如果
type-id
是一个引用,那
么
expression
也必
须
是一个引用。
dynamic_cast
主要用于
类层
次
间
的上行
转换
和下行
转换
,
还
可以用于
类
之
间
的交叉
转换
。
在
类层
次
间进
行上行
转换时
,
dynamic_cast
和
static_cast
的效果是一
样
的;在
进
行下行
转换时
,
dynamic_cast
具有
类
型
检查
的功能,比
static_cast
更安全。
class B{
public:
int m_iNum;
virtual void foo();
};
class D:public B{
public:
char *m_szName[100];
};
void func(B *pb){
D *pd1 = static_cast<D *>(pb);
D *pd2 = dynamic_cast<D *>(pb);
}
在上面的代
码
段中,如果
pb
指向一个
D
类
型的
对
象,
pd1
和
pd2
是一
样
的,并且
对这
两个指
针执
行
D
类
型的任何操作都是安全的;但是,如果
pb
指向的是一个
B
类
型的
对
象,那
么
pd1
将是一个指向
该对
象的指
针
,
对
它
进
行
D
类
型的操作将是不安全的(如
访问
m_szName
),而
pd2
将是一个空指
针
。另外要注意:
B
要有虚函数,否
则
会
编译
出
错
;
static_cast
则
没有
这
个限制。
这
是由于运行
时类
型
检查
需要运行
时类
型信息,而
这
个信息存
储
在
类
的虚函数表(
关
于虚函数表的概念,
详细
可
见
<Inside c++ object model>
)中,只有定
义
了虚函数的
类
才有虚函数表,没有定
义
虚函数的
类
是没有虚函数表的。
另外,
dynamic_cast
还
支持交叉
转换
(
cross cast
)。如下代
码
所示。
class A{
public:
int m_iNum;
virtual void f(){}
};
class B:public A{
};
class D:public A{
};
void foo(){
B *pb = new B;
pb->m_iNum = 100;
D *pd1 = static_cast<D *>(pb); //copile error
D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL
delete pb;
}
在函数
foo
中,使用
static_cast
进
行
转换
是不被允
许
的,将在
编译时
出
错
;而使用
dynamic_cast
的
转换则
是允
许
的,
结
果是空指
针
。
reinpreter_cast
用法:
reinpreter_cast
<type-id> (expression)
type-id
必
须
是一个指
针
、引用、算
术类
型、函数指
针
或者成
员
指
针
。
它可以把一个指
针转换
成一个整数,也可以把一个整数
转换
成一个指
针
(先把一个指
针转换
成一个整数,在把
该
整数
转换
成原
类
型的指
针
,
还
可以得到原先的指
针值
)。
该
运算符的用法比
较
多。
const_cast
用法:
const_cast
<type_id> (expression)
该
运算符用来修改
类
型的
const
或
volatile
属性。除了
const
或
volatile
修
饰
之外,
type_id
和
expression
的
类
型是一
样
的。
常量指
针
被
转
化成非常量指
针
,并且仍然指向原来的
对
象;常量引用被
转换
成非常量引用,并且仍然指向原来的
对
象;常量
对
象被
转换
成非常量
对
象。
Voiatile
和
const
类试
。
举
如下一例:
class B{
public:
int m_iNum;
}
void foo(){
const B b1;
b1.m_iNum = 100; //comile error
B b2 = const_cast<B>(b1);
b2. m_iNum = 200; //fine
}
上面的代
码编译时
会
报错
,因
为
b1
是一个常量
对
象,不能
对
它
进
行改
变
;使用
const_cast
把它
转换
成一个常量
对
象,就可以
对
它的数据成
员
任意改
变
。
注意:
b1
和
b2
是两个不同的
对
象
。