C++中的类型转换
1 C语言中的类型转换
在C语言中我们知道有两种转换,分别是隐式类型转化与显式类型转化
隐式类型转换:编译器在编译阶段自动进行,能转就转,不能转就编译失败
显式类型转换:需要用户自己处理
无论是C语言还是C++中,必须要有一定的关联才可以实现转化!下面总结一下C语言中有哪些可以相互转化的!
int main()
{
int a = 10;
float e = 1.0;
bool b = true;
char ch = 'a';
float* d = &e;
//1 整型与布尔型
a = b;
//2 整形字符型
ch = a;
//3 指针与整形 因为指针也是有大小的
d = (float*)a;
//4 不同类型的指针
d = (float*)&a;
return 0;
}
C++是兼容C语言的,所以以上的转换,C++也是可以做到的!但是C++中也有自己的特色!例如:
1️⃣内置类型与自定义类型之间的转化,例如:const char*与string
class String {
public:
//单参数的默认构造,隐式类型转换
String(const char* ptr = '\0')
{}
};
int main()
{
const char* ptr = "1111";
String s1(ptr);
return 0;
}
2️⃣自定义类型与自定义类型之间的转化,例如:我们在C++11中学过的initializer_list与各种STL容器之间的转化!
3️⃣自定义类型转化为内置类型,只需要重载 operator 内置类型就可以了!
class String {
public:
//单参数的默认构造,隐式类型转换
String(const char* ptr = "")
{}
//可以将自定义类型转化为int
operator int()
{
return 0;
}
};
int main()
{
String s1;
int b = s1;
return 0;
}
2 C++中的类型转换(重点了解)
C++为了规范使用类型转化,加强转化的可视化,特别提出了四种类型的转化方式,如下所示:
2.1 static_cast
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用,static_cast,但它不能用于两个不相关的类型进行转换,也就是说,这个就是相当于解决C语言中的隐式转化类型!
int main()
{
int a = 10;
bool b = true;
char ch = 'a';
//1 整型与布尔型
a = static_cast<int>(b);
//2 整形字符型
ch = static_cast<char>(a)
2.2 reinterpret_cast
reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型!说白了就是为了解决强制类型转化的问题!
int main()
{
int a = 10;
float e = 1.0;
bool b = true;
char ch = 'a';
float* d = &e;
//1 整型与布尔型
a = static_cast<int>(b);
//2 整形字符型
ch = static_cast<char>(a);
//3 指针与整形 因为指针也是有大小的
d = reinterpret_cast<float*>(a);
//4 不同类型的指针
d = reinterpret_cast<float*>(&a);
return 0;
}
2.3 const_cast
const_cast最常用的用途就是删除变量的const属性,方便赋值!
int main()
{
const int a = 1;
//通过指针转换 把const属性删除 从而可以改变a的值
int* p = const_cast<int*>(&a);
*p = 3;
return 0;
}
2.4 dynamic_cast
我们以前在多态那个章节中学习到的,注意在子类对象指针或者引用赋值给父类对象的指针或者引用不属于类型转化,中间是不产生临时变量的,这个叫做赋值兼容!有些地方叫做向上转型!但是父类对象指针或者引用转化成子类对象的指针或者引用就会存在越界访问的问题!具体的例子如下所示:
class A {
virtual void test()
{
cout << "class A " << endl;
}
public:
int _a = 1;
};
class B : public A{
virtual void test()
{
cout << "class B" << endl;
}
public:
int _b = 2;
};
void func(A* ptr)
{
B* b1 = (B*)ptr;
cout << b1->_a << endl;
cout << b1->_b << endl;
}
int main()
{
A a;
B b;
func(&a);//此时传过去就会出现 越界的问题,因为父类对象的地址空间大小比子类对象地址空间大小要小
func(&b);
}
代码运行结果:
解决办法就是引入我们dynamic_cast类型转换:
dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换,我们要注意是:
1️⃣dynamic_cast只能用于父类含有虚函数的类(也就是在多态中)
2️⃣dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
改变如下:
void func(A* ptr)
{
//父类指针转子类指针
//如果检查到ptr传过来时,是父类的指针,返回0
//从而保证不会产生访问越界问题
B* b1 = dynamic_cast<B*>(ptr);
if (b1) {
cout << b1->_a << endl;
cout << b1->_b << endl;
}
}
3 RTTI(了解)
RTTI:Run-time Type identification的简称,即:运行时类型识别。
在C++中主要通过以下几种方式来实现RTTI:
- typeid运算符
- dynamic_cast运算符
- decltype