看过好多次C和C++的类型转换的介绍,但总是记不住,再次提起时又会想不起来。主要是因为不常用到的缘故吧。特意写成一篇博客来,总结一下。
与强制类型转换相对应的是自动类型转换。或者强制类型转换叫显示类型转换,自动类型转换叫隐式类型转换。
自动类型转换会在赋值运算、混合运算、参数传递、返回函数返回值、格式化输出时且当类型出现不一致时发生,转换按数据长度增加的方向进行。
如果不希望一个类型按照自动类型转换的原则发生变化,就需要使用强制类型转换。
C语言的强制类型转换
C语言的强制类型转换很简单,不管什么类型的转换统统是,在要转换的变量前面加小括号,里面写上要转换为的类型。
如,TYPE b = (TYPE)a
C++语言的强制类型转换
C++语言中提供了4种强制类型转换操作符来应对不同场合的应用。
static_cast,从命名上理解是静态类型转换。如int转换成char。
dynamic_cast,从命名上理解是动态类型转换。如子类和父类之间的多态类型转换。
const_cast,从命名上理解就是去除变量的const属性。
reinterpreter_cast,仅仅重新解释类型,但没有进行二进制的转换。
四种操作符的使用方法一致:TYPE B = static_cast<TYPE>(a)
static_cast的用法
其作用和C语言中的类型转换作用一致,属于静态的类型转换。
dynamic_cast的用法
其主要用于基类和派生类之间的动态的类型转换。且仅适用于出现virtual的情况。
假如有一个指向派生类对象的基类指针p(这是多态的基础)。
现在要让一个派生类指针去指向p所指的派生类对象。
若不进行强制类型转换,编译会出错。
若使用static_cast进行静态转换,可以,但不推荐这样转换。
若使用dynamic_cast进行动态转换,可以,这是推荐的做法。
假如有一个指向基类对象的基类指针q。
现在要让一个派生类指针去指向q所指的基类对象。
若不进行强制类型转换,编译会出错。
若使用static_cast进行静态转换,这时候我发现,原基类对象被扩展为了派生类对象。这和我之前看到的资料说的不一样,之前看到的资料显示,static_cast并不会扩展基类。
若使用dynamic_cast进行动态转换,这样转换完之后会返回NULL,即转换不成功。
比如:
#include<stdio.h>
void main()
{
class Base
{
public:
Base():xxx(5)
{}
int xxx;
virtual void foo()
{}
};
class Derived: public Base
{
public:
Derived():yyy(6)
{}
int yyy;
void fun()
{
printf("fun\n");
}
};
Base *p = new Derived();
//Derived *p1 = p; //错误
//Derived *p1 = static_cast<Derived*>(p);
Derived *p1 = dynamic_cast<Derived*>(p);
Base *q = new Base();
//Derived *q1 = q; //错误
Derived *q1 = static_cast<Derived*>(q);
//Derived *q1 = dynamic_cast<Derived*>(q); q1会是NULL
(*q1).xxx = 100;
(*q1).yyy = 200;
(*q1).fun();
(*q).xxx = 300;
printf("%d %d %d\n",(*q).xxx,(*q1).xxx,(*q1).yyy);
}
const_cast的用法
如果const类型的变量直接赋给非const变量,不需要类型转换,后者直接就是非const类型的。const_cast一般是要转换指向const的指针或引用类型,从而能修改const类型变量的值。
比如,
void main()
{
class A
{
public:
A():xxx(5)
{}
int xxx;
};
const A a;
A &b = const_cast<A&>(a);
b.xxx = 6;
printf("a = %d\n",a.xxx);
printf("b = %d\n",b.xxx);
}
reinterpreter_cast的用法
这种强制转换方式仅仅重新解释类型,不进行实质二进制的转换。转换的类型必须是一个指针、引用、算术类型、函数指针或者成员指针。最普通的用途就是在函数指针类型之间进行转换。
比如,
#include<stdio.h>
int fun1()
{
printf("fun1\n");
return 1;
}
void main()
{
typedef void(*FunPtr)();//函数指针
FunPtr a;
//a = &fun1; //错误
a = reinterpret_cast<FunPtr>(&fun1);
a();
}
PS遗留问题:
用static_cast将基类指针转换为派生类指针的时候,我在VS2010上的实验结果和看到的资料不一致。有待继续研究。