C语言中的类型转换
#include <stdio.h>
#include <Windows.h>
int main() {
int i = 1;
// 隐式类型转换
double d = i;
printf("%d\t%.2f\n", i, d);
int* p = &i;
// 强制类型转换
int address = (int)p;
printf("%p\t%d\n", p, address);
system("pause");
return 0;
}
C语言本身是一个强类型的语言, 但是对于相近类型还是会存在隐式转换的问题, 这使得C语言埋下了很多的坑, 比如说int与size_t的隐式类型转换导致循环不符合预期, 以及int(a) = int(a) + double(b)这种多次隐式类型转换导致损失效率等等.
不同类型能否可以进行强制类型转换, 这是由编译器决定的, 上述代码在vs下正常通过, 但是在其他编译器(比如说gcc)就不一定了.
C++强制类型转换
为了解决C语言中由于不明确的隐式类型转换而导致的各种问题, C++引入了可视化的强制类型转换. 但是这并没有从根本上解决问题, 仅仅是一种期望
static_cast:
静态转换, 用于两个相近类型的隐式转换
int main() {
int i = 1;
double d = static_cast<double>(i);
printf("%d\t%.2f\n", i, d);
return 0;
}
reinterpret_cast:
重新诠释转换, 用于两个不同类型的强制类型转换
int dosomething(int i) {
cout << "dosomething" << endl;
return 0;
}
int main() {
typedef void(*FUN)();
FUN f = reinterpret_cast<FUN>(dosomething);
f();
}
const_cast:
const转换, 用于删除const属性
int main() {
const int i = 1;
int* p = const_cast<int*>(&i);
*p = 100;
cout << i << endl;
cout << *p << endl;
}
i的值并没有改变, 这是因为编译器优化的结果, 编译器将旧值i保存在寄存器中, 而i在内存中已经被修改了, 但是每次打印i的时候编译器都从寄存器中取而不是内存中.
volatile const int i = 1;
可以通过volatile关键字来防止编译器优化, 每次都去内存中取值
dynamic_cast:
动态转换, 用于将一个父类对象的指针转换为子类对象的指针或引用. 前提是这个父类具有多态性(即里面必须有虚函数表)
class A {
public:
virtual void show() {
cout << "A" << endl;
}
};
class B : public A {
public:
virtual void show() {
cout << "B" << endl;
}
};
void fun(A* pa) {
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout << pb1 << endl;
cout << pb2 << endl;
pb1->show();
}
void fun1() {
A* pa = new A;
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout << pb1 << endl;
cout << pb2 << endl;
pb1->show();
}
将父类对象强转为子类对象, static_cast没有强转成功依然指向父类对象, 而dynamic_cast直接被置nullptr
void fun2() {
A* pa = new B;
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout << pb1 << endl;
cout << pb2 << endl;
pb1->show();
pb2->show();
}
将指向的子类对象的父类指针强转为子类指针, static_cast与dynamic_cast都成功了.
建议:
避免使用强制类型转换
C++类型强转延伸
explicit:
阻止拷贝构造隐式转换为构造的过程
class A {
public:
explicit A(int a) : _a(a) {
cout << "A(int a)" << endl;
}
A(const A& a) : _a(a._a) {
cout << "A(const A& a)" << endl;
}
int getA() {
return _a;
}
private:
int _a;
};
int main() {
A a1(1);
cout << a1.getA() << endl;
//A a2 = 2; //不允许 A tmp(1) ---> A a2(tmp)
//cout << a2.getA() << endl;
return 0;
}
RTTI:
Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:
- typeid运算符
- dynamic_cast运算符