目录
1. C的类型转换
1. 显式类型转换
void Test1(void)
{
// 显式类型转换
int* ptr = nullptr;
//int i = ptr; // 默认情况下,指针不支持隐式类型转换为整形
int i = (int)ptr; // 但是可以支持强转
}
2. 隐式类型转换
void Test2(void)
{
double d = 1.1;
int i = d; //意义相近的类型,支持隐式类型转换
}
3. 总结
2. C++强制类型转换
2.1. static_cast
void Test3()
{
// 静态类型转换 static_cast
// 支持合理的转换
double d = 1.1;
int i = static_cast<int>(d);
// 不支持合理的转换,例如将指针转换为整形
int* ptr = nullptr;
int i = static_cast<int>(ptr); // 编译报错
}
2.2. reinterpret_cast
void Test4(void)
{
// 重新解释类型转换 reinterpret_cast
// 可以将一个指针转化为一个整形
int* ptr = nullptr;
int i = reinterpret_cast<int>(ptr);
std::cout << ptr << std::endl;
// 也可以将一个整形转化为指针
int j = 5;
int* ptr1 = reinterpret_cast<int*>(i);
}
2.3. const_cast
void Test5(void)
{
const int i = 5;
// int* ----- const int*
int*p = const_cast<int*>(&i);
*p = 10;
std::cout << i << std::endl;
std::cout << *p << std::endl;
}
void Test5(void)
{
volatile const int i = 5;
int*p = const_cast<int*>(&i);
*p = 10;
std::cout << i << std::endl;
std::cout << *p << std::endl;
}
顺便,在这里提醒一下,上面都是C++规范的操作,有时候,它也可以这样:
void Test5(void)
{
volatile const int i = 5;
//int*p = const_cast<int*>(&i); // C++规范做法
int* p = (int*)&i; // C++兼容C的做法,当然结果一致
*p = 10;
std::cout << i << std::endl;
std::cout << *p << std::endl;
}
2.4. dynamic_cast
class base
{
public:
int _a = 5;
};
class derive : public base
{
public:
int _b = 10;
};
void Test6(void)
{
derive d_target;
// C++ 支持派生类向上"转型"为基类
base b_target = d_target; // 派生类对象切片为基类对象
// 如果这是类型转换,这里都编不过,因此这些都不是类型转换
base* p_target = &d_target; // 派生类指针切片为基类指针
base& r_target = d_target; // 派生类引用切片为基类引用
// 例如:
double d = 1.1;
//C++兼容C的不规范的转换
int& i = d; // 这里编译报错,为什么?
// C++规范的转换
int& i = static_cast<int>(d); // 但同样会报错
// 因为这里是类型转换,而类型转换都会生成一个临时变量,临时变量是右值
// 因此我们这里需要加const,引用右值
const int& i = static_cast<int>(d);
}
void Test6(void)
{
base b_target;
derive d_target;
derive new_target = reinterpret_cast<derive>(b_target); //编译报错
//derive new_target = (derive)(b_target);
}
void func(base* ptr)
{
// 这里是支持的,可以将父类指针强转为子类指针
derive* dp = reinterpret_cast<derive*>(ptr);
std::cout << dp->_a << " : " << dp->_b << std::endl;
dp->_a = 5;
dp->_b = 10;
}
void Test7(void)
{
base b;
derive d;
func(&b);
func(&d);
}
class base
{
public:
virtual void func(void){}
public:
int _a = 5;
};
class derive : public base
{
public:
int _b = 10;
};
void func(base* ptr)
{
derive* dp = dynamic_cast<derive*>(ptr);
// 如果ptr指向子类对象,转换成功
if (dp != nullptr)
{
std::cout << dp->_a << " : " << dp->_b << std::endl;
dp->_a = 10;
dp->_b = 20;
}
// 如果ptr指向父类对象,转换失败,并返回空
else
{
std::cout << dp << std::endl;
}
}
void func(base& ptr)
{
// 如果ptr指向子类对象,转换成功
// 如果ptr指向父类对象,抛异常,具体为:std::bad_cast异常
derive dp = dynamic_cast<derive&>(ptr);
std::cout << dp._a << " : " << dp._b << std::endl;
dp._a = 10;
dp._b = 20;
}
扩展问题:
namespace tmp
{
class base1
{
public:
virtual void func(void){}
public:
int _a1 = 5;
};
class base2
{
public:
virtual void func(void){}
public:
int _a2 = 10;
};
class derive : public base1, public base2
{
public:
int _b = 20;
};
}
void Test8(void)
{
tmp::derive d_target;
tmp::base1* bp1 = &d_target;
tmp::base2* bp2 = &d_target;
std::cout << bp1 << std::endl;
std::cout << bp2 << std::endl;
std::cout << "------------------" << std::endl;
// C++兼容C语言的类型强转
tmp::derive* dp1 = (tmp::derive*)bp1;
tmp::derive* dp2 = (tmp::derive*)bp2;
std::cout << dp1 << std::endl;
std::cout << dp2 << std::endl;
std::cout << "------------------" << std::endl;
// C++规范的类型强转
tmp::derive* dp3 = reinterpret_cast<tmp::derive*>(bp1);
tmp::derive* dp4 = reinterpret_cast<tmp::derive*>(bp2);
std::cout << dp3 << std::endl;
std::cout << dp4 << std::endl;
std::cout << "------------------" << std::endl;
// C++的动态转换
// 要求基类必须是多态类型
tmp::derive* dp5 = dynamic_cast<tmp::derive*>(bp1);
tmp::derive* dp6 = dynamic_cast<tmp::derive*>(bp2);
std::cout << dp5 << std::endl;
std::cout << dp6 << std::endl;
std::cout << "------------------" << std::endl;
}
3. 为什么需要强制类型转换
.
4. RTTI
int i = 10;
//推导一个对象的类型,其结果可以定义一个新的对象
decltype(i) j = 0;