C++知识点 – C++的类型转换
文章目录
- C++知识点 -- C++的类型转换
- 一、C语言中的类型转换
- 二、C++的强制类型转换
- 1.static_cast
- 2.reinterpret_cast
- 3.const_cast
- 4.dynamic_cast
一、C语言中的类型转换
void test()
{
int i = 0;
//隐式类型转换(意义相近的类型)
double d = i;
printf("%d, %.2f\n", i, d);
int* p = &i;
//显式的强制类型转换(意义不相近的类型,但是转换后的值有意义)
int address = (int)p;
printf("%x, %d\n", p, address);
}
比较符号两边也会发生隐式类型转换;
如果pos == 0,这里end被提升成了无符号整型,当end减到0时,再–end,就会成-1,而对于无符号整型来说,-1就是最大的数;
因此程序进入了死循环;
二、C++的强制类型转换
(1)兼容c的隐式类型转换和强制类型转换;
(2)期望用户使用c++的显式强制类型转换;
1.static_cast
static_cast用于非多态类型的转换,编译器隐式执行的任意类型转换都可用static_cast,但不能用于两个不相关的类型之间转换;(类似于c的隐式类型转换,转换意义相近的类型)
void test()
{
double d = 5.35;
int i = static_cast<int>(d);
cout << i << endl;
}
2.reinterpret_cast
reinterpret_cast通常用于将一种类型转换为另一种不同的类型;(类似于c的强制类型转换,类型不同但转换后的值有意义)
void test()
{
double d = 5.35;
int i = static_cast<int>(d);
cout << i << endl;
int* p = reinterpret_cast<int*>(i);
}
3.const_cast
const_cast最常用的就是删除变量的const属性,方便赋值;
c++中的const对象并没有存在常量区,而是存在栈上,所以叫常变量,能够通过这种方式修改
void test()
{
const int a = 2;
int* p = const_cast<int*>(&a);
(*p)++;
cout << a << endl;
cout << *p << endl;
}
以上代码的输出结果其实是:
但是a在实际的存储空间上还是被改变了的;
原因就在于编译器对于const类型的变量有优化,认为const变量不会被修改;
直接在a初始化的时候就把它放进一个寄存器中,读取的时候不用在内存中取,而是直接去寄存器中取,所以还是2
但是*p实是在内存中取的,所以是3;
给a加上volatitle关键字表示不去优化这个变量;
void test()
{
volatile const int a = 2;
int* p = const_cast<int*>(&a);
(*p)++;
cout << a << endl;
cout << *p << endl;
}
输出结果a就变为3了;
4.dynamic_cast
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针/引用(动态转换);
向上转型:子类对象指针/引用 -> 父类对象指针/引用(不需要转换,赋值兼容)
向下转型:父类对象指针/引用 -> 子类对象指针/引用(用dynamic_cast转换是安全的)
注意:
(1)dynamic_cast只能用于父类含有虚函数的类;
(2)dynamic_cast会事先检查转换是否成功,如果能成功就转换,不能就返回0;
class A
{
public:
virtual void f(){}
public:
int _a = 0;
};
class B : public A
{
public:
int _b = 1;
};
void func(A* pa)
{
B* pb = (B*)pa;
pb->_a++;
pb->_b++;
}
A*是父类指针,可能指向父类对象,也可能指向子类对象;但是指向子类对象无法访问子类独有的成员;
如果使用C中的强制类型转换,会发生越界
class A
{
public:
virtual void f(){}
public:
int _a = 0;
};
class B : public A
{
public:
int _b = 1;
};
void func(A* pa)
{
//如果pa指向子类,那么可以转换,转换表达式返回正确的地址
//如果pa指向父类,那么不可以转换,转换表达式返回nullptr
B* pb = dynamic_cast<B*>(pa); // 安全的
if (pb)
{
cout << "转换成功" << endl;
pb->_a++;
pb->_b++;
cout << pb->_a << ":" << pb->_b << endl;
}
else
{
cout << "转换失败" << endl;
pb->_a++;
cout << pb->_a << endl;
}
}
void test()
{
B b;
func(&b);
}
使用dynamic_cast转换是安全的;
如果pa指向子类,那么可以转换,转换表达式返回正确的地址;
如果pa指向父类,那么不可以转换,转换表达式返回nullptr;
例:
强制类型转换之后,ptr2指向的地址会改变,变成子类的地址,与dynamic_cast是一样的