1.C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参和实参类型不匹配,或者返回值类型和接收返回值类型不一致,就会发生类型转换。
C语言中的类型转换分为两种:隐式类型转换和强制类型转换
1.1隐士类型转换【相近类型,意义相近】
void test()
{
int i=1;
double d=i;
printf("%f,%f",d,i);
}
输出:
1.00000 0.00000
解释:
i按照%f的方式输出时,发生了整形提升。
浮点数在内存的存储规则为:
(-1)^S*M*2^E
S:一个比特位,表示数的正负
M:23个比特位,有效数字,科学计数法表示
E:8个比特位,表示指数位
需要注意的是:E在存储到内存的时候,需要加上一个中间数127
1.2.强制类型转换
强制类型转换针对的是意义相差很远的类型,比如int类型和指针类型
void test()
{
int i=0;
int* p=&i;
int address(int)p;
printf("%p,%d\n",p,address);
}
输出:
0133FA4C,20183628
2.C++的类型转换
2.1相近类型转换–static_cast
static_cast用于相近类型,意义相似的类型。static_cast用于非多态类型的转换(静态转换)。
void test()
{
double d=11.11;
int a=static_cast<int>(d);
cout<<a<<endl;
}
输出:11
2.2强制类型转换—reinterpret_cast
void test()
{
double d=12.34;
int a=static_cast<int>(d);
cout<<a<<endl;
int*p=reinterpret_cast<int*>(a);
cout<<p<<endl;
}
输出:
12
0000000C
2.3去掉对象const属性—const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值
const int ca=2;
int*pi=const_cast<int*>(&ca);
*pi=3;
cout<<ca<<endl;
cout<<*pi<<endl;
输出:
2 3
为什么ca输出的是2?
对于ca,编译器做出了优化,考虑到const类型被修改的可能性很小,所以编译器将ca存放在寄存器中。
如果修改为
volatile const int ca=2;
int*pi=const_cast<int*>(&ca);
*pi=3;
cout<<ca<<endl;
cout<<*pi<<endl;
输出:
3 3
volatile表示强制从内存中取出变量值
2.4dynamic_cast
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
- 向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)【多态和切片原理】
- 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
-
dynamic_cast只能用于父类含有虚函数的类
-
dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
dynamic_cast底层实现使用了虚表的结构
class A
{
public:
void f()
{}
};
class B :public A
{
void f()
{}
};
void test(A* pa)
{
B* ptr1 = static_cast<B*>(pa);
B* ptr2 = dynamic_cast<B*>(pa);
}
int main()
{
A a;
B b;
test(&a);
test(&b);
return 0;
}
class A
{
public:
virtual void f()
{}
};
class B :public A
{
void f()
{}
};
void test(A* pa)
{
B* ptr1 = static_cast<B*>(pa);
B* ptr2 = dynamic_cast<B*>(pa);
}
int main()
{
A a;
B b;
test(&a);
test(&b);
return 0;
}