目录
一,C类型转换
在C语言中,如赋值运算符左右两侧类型不同,或形参与实参类型不匹配,或返回值类型与接受类型不一致时,此时就会发生类型转换;C语言中总共有两种类型转换;
- 隐式类型转换,编译器在编译阶段自动进行,可能会丢失数据精度,如不能转就会编译失败;
- 显式类型转换,需用户自己处理,显式指定转换的类型,代码混合在一起会造成代码不够清晰;
缺陷:转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换;
int a = 1;
double b = a; //隐式类型转换
int c = (int)b; //显式类型转换
二,C++强制类型转换
C++提出了自己的类型转化风格,需注意C++兼容C语言,所以C++中还是可以使用C语言的转化风格;标准C++为了加强类型转换的可视性,引入了四种强制类型转换操作符;
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
static_cast
- 静态转换,适用于非多态类型间的转换,基本类型间的转换,子类与基类间的转换,及整形与枚举间的转换;
- 编译器隐式执行的任何类型转换都可用static_cast,但不能用于两个不相关的类型进行转换;
- 只能在编译时安全的类型转换,不能用于运行时;
//基本类型间的转换
double d = 12.34;
int a = static_cast<int>(d);
//子类与基类间的转换
class A {};
class B : public A {};
A* myAnimal = new A();
B* myDog = static_cast<B*>(myAnimal);
//整形与枚举间的转换
enum color { red, green, blue };
int a = static_cast<int>(blue);
reinterpret_cast
- 通常为操作符的位模式提供较低层次的重新解释,用于将一种类型转换位另一种不同的类型;
- 应谨慎使用,无运行时安全检查,可能导致程序崩溃或数据损坏;
//一个整数值的比特位直接解释为另一个类型的对象
int num = 0x12345678;
int* p = reinterpret_cast<int*>(num);
typedef void (*FUNC)();
int DoSomething(int i)
{
cout << "DoSomething" << endl;
return 0;
}
void Test()
{
//函数指针DoSomething的类型转换为FUNC
FUNC f = reinterpret_cast<FUNC>(DoSomething);
f();
}
const_cast
- 最常用的用途就是删除变量的const属性(即解除变量的常量属性),方便赋值;
const int a = 10;
int* pa = const_cast<int*>(&a); //原本&a的类型const int*
*pa = 20;
const int num = 10;
int& var = const_cast<int&>(num);
var = 20;
dynamic_cast
- 通常用于在运行时,处理多态类型(即含有虚函数的类)的向下转换;
- 用于将一个父类对象的指针/引用转换位子类对象的指针/引用(动态转换);
- 向上转型,子类对象指针/引用 -> 父类指针/引用(不需要转换,赋值兼容规则);
- 向下转型,父类对象指针/引用 -> 子类指针/引用(用dynamic_cast转型是安全的);
注:
- dynamic_cast只能用于含有虚函数的类;
- dynamic_cast会先检测是否能转换成功,能成功则转换。不能则返回0;
class A
{
public:
virtual void f(){}
};
class B :public A
{};
void fun(A* pa)
{
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout << "pb1:" << pb1 << endl;
cout << "pb2:" << pb2 << endl;
}
int main()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}
注意,强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会;强烈建议,避免使用强制类型转换;
explicit
- explicit关键字,阻止经过转换为构造函数,进行的隐式转换的发生;
class A
{
public:
explicit A(int a)
{
cout << "A(int a)" << endl;
}
A(const A& a)
{
cout << "A(const A& a)" << endl;
}
private:
int _a;
};
int main()
{
A a1(1);
//隐式转换,A tmp(1),A a2(tmp)
A a2 = 1; //报错
return 0;
}
三,RTTI
- Run-Time Type Identification 简称,即运行时类型识别;用于在程序运行时,确定对象的类型;
- 提供两个关键字:
- typeid运算符,返回给定对象的确切动态类型信息,使用方法
typeid(object)
或typeid(type)
,其返回类型为type_info类; - dynamic_cast运算符,可在运行时执行通过向上转型而得到的一个基类指针或引用的向下转型;
- typeid运算符,返回给定对象的确切动态类型信息,使用方法
#include <iostream>
#include <typeinfo>
class Foo {};
class Bar : public Foo {};
int main() {
Foo* foo1 = new Foo();
Foo* foo2 = new Bar();
if (typeid(*foo1) == typeid(Foo)) {
std::cout << "foo1 is an instance of Foo\n";
}
if (typeid(*foo2) == typeid(Bar)) {
std::cout << "foo2 is an instance of Bar\n";
}
else if (typeid(*foo2) == typeid(Foo)) {
std::cout << "foo2 is an instance of Foo\n";
}
delete foo1;
delete foo2;
return 0;
}
type_info
存储关于类型的信息,由typeid操作返回,可用于比较两个类型;当typeid一个空指针时,会抛出bad_typeid异常;
type相关的关键字
- typedef,重定义新类型名;
- typename,用于模板表示类型名;
- decltype,用于推导表达式的类型并返回该类型;
- typeid,用于获取类型信息;
- type_info(类),存储typeid返回的类型;
- type_index(类),获取类型的标识符;