在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就会发生类型转化。
C语言总共有两种形式的类型转换:隐式类型转换
和显示类型转换
(强制类型转化)
void Test ()
{
int i = 1;
// 隐式类型转换
double d = i;
int* p = &i;
// 显示的强制类型转换
int address = (int) p;
}
缺陷:
转换的可视性比较差,所有的转换形式都是相同形式书写,难以跟踪错误的转换
C语言风格的转换格式很简单,但是也有缺点:
因此C++提出了自己的类型转换风格,引入了四种命名的强制类型转换操作符
static_cast,reinterpret_cast,const_cast,dynamic_cast
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,即可用于意义相近的类型转换
void test1()
{
double a = 12.34;
//都是表述数值
int b = static_cast<int>(a);
cout << b << endl;
}
reinterpret(重新解释),该操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型
void test2()
{
double a = 12.34;
//都是表述数值
int b = static_cast<int>(a);
//数值转换成地址
int*p = reinterpret_cast<int*>(b);
}
const_cast最常用的用途就是删除变量的const属性,方便赋值
void test3()
{
const int a = 2;
//删除const属性
int *p = const_cast<int*>(&a);
*p = 3;
cout << *p << endl;
}
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针/引用(动态转换)
向上转型:子类指针/引用–>父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类指针/引用–>子类指针/引用(用dynamic_cast转是安全的)
注意:
为什么说向下转型用dynamic_cast是安全的,强制转换为什么不安全?
比如这样一个继承体系
class A
{
public:
virtual void fun()
{}
private:
int _x;
};
class B :public A
{
private:
int _y;
int _z;
};
B继承A,但B拥有自己的成员变量,如果强制类型转换,情况如下:
因为B比A大,所以B的指针能访问的空间更多,但是这部分并不属于A。如果原先是指向A类型对象的指针,那么强转成B类型的指针,访问权限变大,但那部分并不属于A类型对象,这就会造成
越界
强制类型转换并不会管原先指向的到底是父类对象还是子类对象,都会转换成功。
而dynamic_cast会检查,如果是原先是父类对象,则转换失败返回0,如果是子类对象,则转换成功。
void fun(A* pa,const string&str)
{
// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
cout << str << "转换" << endl;
B* pb1 = (B*)(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout << "pb1:" << pb1 << endl;
cout << "pb2:" << pb2 << endl << endl;
}
void test4()
{
A a;
B b;
fun(&a,"父类对象");
fun(&b,"子类对象");
}
可以看到,强制转换不管父类还是子类对象都会发生转换,而dynamic_cast只有原先指向子类时才会发生转换
注意:
强制类型转换关闭或者挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方式达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。
强烈建议:避免使用强制类型转换
RTTI:Run-time Type identification的简称,即:运行时类型识别
有以下三种方式:
dynamic_cast:可以识别一个指针/引用,指向的是父类对象还是子类对象
decltype:自动类型推导
和auto类似,但是decltype是通过其他对象获取类型
auto x=1;//auto通过=号右边推导
decltype(x) y=1;//decltype通过x推导
auto要求变量必须初始化,因为auto根据变量的初始值来推导变量类型,如果不初始化,变量的类型就无法推导。
而decltype不需要初始化,所以decltype可以适用于只要自动推导类型
的场景
比如如下场景:
function<int> add=[](int a,int b)->int{ return a+b; };
set<int,decltype(add)> s;
感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。