隐式类型转换(意义相近的类型)
int i = 1;
// 隐式类型转换(意义相近的类型)
double d = i;
printf("%d, %.2f\n", i, d);
显示的强制类型转换(意义不相近的类型,值转换后有意义)
int main()
{
int a = 1;
int* p = &a;
//int address = p; //这样没法隐式类型转换会报错
int address = (int)p; //强制类型转换没问题
printf("%x, %d\n", p, address);
}
c++也支持c的类型转换,但是c++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符
这个就像c中的隐式类型转换,只不过显示的写了出来,static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换
int main()
{
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
return 0;
}
类似于c的显示强制类型的转换,一般用于将一种类型转换为另一种不同的类型
int main()
{
int a = 10;
int* p = reinterpret_cast<int*>(a); // 把int 强转为 int*
return 0;
}
能够删除变量的const属性
int main()
{
const int a = 2;
//int* p = const_cast<int*>(&a);
int* p = (int*)&a; // c的那一套也可以
*p = 3;
cout << a << endl;
cout << *p << endl;
return 0;
}
但是上边的代码会出现一个问题,就是运行结果显示,a还是2,不过当我们打开监视窗口可以看到a其实已经被改成3了,这是什么原因呢?
a被const修饰,编译器以为不会被修改,所以加载到寄存器,虽然内存中已经被改了但是寄存器里面的还是2,cout的时候直接去寄存器读,所以打印出来是2
我们可以在定义a变量的时候加上 volatile关键字,这样编译器处理的时候就会去内存中读取数据,这样,运行结果就变成3 3了。
注:
用于将一个父类对象的指针或者引用转换为子类的指针或者引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用 (不需要转换,赋值兼容规则)向下转型:父类对象指针/引用->子类指针/引用 (用dynamic_cast转型是安全的)
class A
{
public:
virtual void f(){}
public:
int _a = 0;
};
class B : public A
{
public:
int _b = 1;
};
// A*指针pa有可能指向父类,有可能指向子类
void fun(A* pa)
{
// 如果pa是指向子类,那么可以转换,转换表达式返回正确的地址
// 如果pa是指向父类,那么不能转换,转换表达式返回nullptr
B* pb = dynamic_cast<B*>(pa); // 安全的
//B* pb = (B*)pa; // 不安全
if (pb)
{
cout << "转换成功" << endl;
pb->_a++;
pb->_b++;
cout << pb->_a << ":" << pb->_b << endl;
}
else
{
cout << "转换失败" << endl;
pa->_a++;
cout << pa->_a << endl;
}
}
int main()
{
A aa;
// 父类对象无论如何都是不允许转换成子类对象的
/*B bb = dynamic_cast<B>(aa);
B bb = (B)aa;*/
B bb;
fun(&aa);
fun(&bb);
//fun(nullptr); 转换失败并且报错
return 0;
}
细节部分:
class A1
{
public:
virtual void f(){}
public:
int _a1 = 0;
};
class A2
{
public:
virtual void f(){}
public:
int _a2 = 0;
};
class B : public A1, public A2
{
public:
int _b = 1;
};
int main()
{
B bb; //定义子类对象
A1* ptr1 = &bb;
A2* ptr2 = &bb;
cout << ptr1 << endl;
cout << ptr2 << endl << endl; //这两个地址是不同的
B* pb1 = (B*)ptr1;
B* pb2 = (B*)ptr2;
cout << pb1 << endl;
cout << pb2 << endl << endl;
B* pb3 = dynamic_cast<B*>(ptr1);
B* pb4 = dynamic_cast<B*>(ptr2);
cout << pb3 << endl;
cout << pb4 << endl << endl;
return 0;
}
可以看到,强转成子类指针,和dynamic_cast都可以将指针位置偏移到头上
总结:
Run-time Type identification :运行时类型识别
c++通过以下方式支持RTTI