相对于C,C++由于引入了类,类型转换要更为复杂,除了C中原有的基本类型的显式(强制)和隐式类型转换外,还多了类类型之间,以及类与内置类型之间的相互转换。
1 基本类型的隐式转换
C和C++基本类型的转换主要发生在赋值语句和表达式计算这两个时候。
a)赋值转换
一个基本的原则:1)将一个取值范围大的值赋值给一个取值范围小的变量时,系统保留大值的低字节;
例如:
int a = 0x1111FFFF; short b = a;//此时b = 0xFFFF
2)将一个取值范围小的值赋值给一个取值范围大的变量时,作符号位扩展
例如:(注意0xFFFFFFE0是补码)
char ch = 0xE0; int i = ch;//此时i内存中存储的是0xFFFFFFe0;
b)表达式计算转换
这种情况主要针对一个表达式中出现了不同类型的变量,表示范围小的变量会被转换为较大的类型。
需要注意的是,当同一类型的有符号变量向无符号变量转换时,内存中的内容并没有改变,只是对内容的解释发生了改变。
例如:
short a = 0xFFF0; cout << a << endl;//输出a为-16
unsigned short b = a; cout << b << endl;//输出b为65520
此外,在函数实参与形参传递、函数返回值处,也可能发生隐式类型转换,原理相同,就不再赘述;
并且除了基本类型的隐式转换外,在类类型之间也存在隐式转换,即类的对象,指针,引用之间的上行转换,为了方便叙述,这些内容就放到本节介绍C++显式类型转换操作符中进行介绍了。
2 显式类型转换
下面介绍显式的类型转换。在C中,显式类型转换主要用于指针类型的相互转换(除了转换成void*),例如在C中我们动态分配内存时,经常用到的malloc函数,下面的代码就是将malloc返回的void*转换为int*。
int *p = (int *)malloc(sizeof(int) * 10);
而在C++中,则引入了四个显式类型转换操作符用于显示类型转换。
1)reinterpret_cast
与刚刚介绍的C中使用圆括号加类型名的显式转换方式效果相同
2)const_cast
将const型的变量转换为非const类型
3)static_cast
适用于上面介绍的隐式类型转换,以及公有继承关系的派生类对象、指针、引用向基类的对象、指针、引用的隐式转换(上行转换),换言之,static_cast适用于所有编译器可以自动完成的隐式转换。但需要注意的是用static_cast完成类指针和引用的下行转换时,虽然可以编译运行,但是这是不安全的。例如:pb->b会指向未知的地方。
class A{
public:
int a;
};
class B :public A{
public:
int b;
};
int main(){
A a, *pa;
B b, *pb;
a.a = 1; b.a = 21; b.b = 22;
pa = static_cast<A*>(&b);//上行转换,正确且类型安全
A &ra = static_cast<A&>(b);//上行转换,正确且类型安全
pb = static_cast<B*>(&a);//下行转换,编译通过但不安全
cout << pa->a << endl;//输出21
cout << ra.a << endl;//输出21
cout << pb->a << endl;//输出1
cout << pb->b << endl;//输出垃圾值
}
4)dynamic_cast
主要适用于公有继承关系的基类和派生类的指针和引用之间的上行和下行转换,并且其操作数必须包含多态类型(基类中必须包含虚函数),当进行上行转换时,效果和static_cast是一样的。而当进行下行转换时,dynamic_cast会进行类型检查,举例如下:由于pa1指向的是A类的对象,因此在进行dynamic_cast时发现下行转换不安全,返回null;而pa2指向的是B类的对象,完全可以将pa2转换成B类的指针。
class A{
public:
int a;
virtual void print(){
cout << "class A" << endl;
}
};
class B :public A{
public:
int b;
virtual void print(){
cout << "class B" << endl;
}
};
int main(){
A a;
B b;
A *pa1 = &a;
A *pa2 = &b;
B *pb1 = dynamic_cast<B*> (pa1);
B *pb2 = dynamic_cast<B*> (pa2);
cout << pb1 << endl;//00000000
cout << pb2 << endl;//008FFE9C
}
3 用户自定义的隐式转换
除了编译完成的自动转换,用户还可以为自定义的类型设置一些隐式转换。下面这两个函数其实是相反的两个过程。
class Intergral {
public:
Intergral(int a = 0) {//转换构造函数
real = a;
}
operator int() {//类型转换函数
//该函数没有返回类型,但可以return一个int值;
return real;
}
private:
int real;
};
int main() {
Intergral a = 2;
int b = a;
cout << b << endl;
}
1)转换构造函数
定义一个类的转换构造函数,将其他的类型转换为该类的对象。需要注意转换构造函数的非默认参数不能超过一个
2)类型转换函数
定义一个类的类型转换函数,将该类的对象转换成其他类型。注意转换构造函数没有参数,没有返回值,函数名为其他类型的名称(并不局限于基本类型,可以是自定义类型)。
就先总结到这里,有不足之处还望各位不吝指正。