一、静态类型转换(static_cast)
静态类型的转换主要用于基本类型之间的转换,比如int类型转换为double类型。但是static_cast也可以支持上下行的转换(存在继承关系之间的转换)
基本类型之间的转换举例
上下行转换的举例
#include <iostream>
#include<typeinfo>
using namespace std;
class A
{
public:
int a=1;
int b=2;
int c=3;
};
class B:public A
{
public:
int d=4;
int e=5;
int f=6;
};
int main()
{
//用指针实例化一个类对象
A *ptr_a=new A();
B *ptr_b=new B();
cout<<"A的数据:"<<ptr_a->a<<endl<<"B的数据:"<<ptr_b->d<<endl;
//A指向B,B指向A
A *ptr_a1=static_cast<A *>(new B());//上行转换(子类强行转换为父类),安全
B *ptr_b1=static_cast<B *>(new A());//下行转换(父类强行转换为子类),不安全,容易越界,因为父类只能访问自己的
cout<<"A指针访问数据:"<<ptr_a1->c<<endl<<"B指针访问数据:"<<ptr_b1->f<<endl;
return 0;
}
从输出结果看,下行转换是支持的(输出了数据),结合源代码可知,26708不是我们想要输出的数据,指针访问越界了(A是基类,只能访问自己的空间,也证明了继承关系不具有双向性,继承关系是单向的)
二、动态类型转换(dynamic_cast)
动态类型的转换主要用来转换存在继承关系的指针或引用类型,相比于静态类型转换(static_cast),动态类型转换会进行类型检查,如果转换不安全会抛出异常错误信息
#include <iostream>
#include<typeinfo>
using namespace std;
class A
{
public:
int a=1;
int b=2;
int c=3;
};
class B:public A
{
public:
int d=4;
int e=5;
int f=6;
};
int main()
{
//用指针实例化一个类对象
A *ptr_a=new A();
B *ptr_b=new B();
cout<<"A的数据:"<<ptr_a->a<<endl<<"B的数据:"<<ptr_b->d<<endl;
//A指向B,B指向A
A *ptr_a1=dynamic_cast<A *>(new B());//上行转换(子类强行转换为父类),安全
B *ptr_b1=dynamic_cast<B *>(new A());//下行转换(父类强行转换为子类),不安全,容易越界,因为父类只能访问自己的
cout<<"A指针访问数据:"<<ptr_a1->c<<endl<<"B指针访问数据:"<<ptr_b1->f<<endl;
return 0;
}
这段代码运行之后会报异常信息
D:\study\STL\class_cast\main.cpp:31: error: cannot dynamic_cast '(operator new(12u), (<statement>, ((A*)<anonymous>)))' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
B *ptr_b1=dynamic_cast<B *>(new A());//下行转换(父类强行转换为子类),不安全,容易越界,因为父类只能访问自己的
^
说明dynamic_cast只支持上行类型转换(子类转换为父类)。
三、常量类型转换(const_cast)
常量类型转换常用来去除指针或引用的常量性。对于指针或引用,常量转换可以将其修改为非常量。例如:
tips:通过指针b可以修改第三方的值
需要注意的是如果修饰某个变量为常量,则不可更改数据,但是未修饰的变量可以更改数据
#include <iostream>
using namespace std;
int main()
{
int c=6;
const int *a=&c;//const修饰的a为常量属性,a不可被修改
int *b=const_cast<int *>(a);//类型转换后可以被修改
cout<<*a<<" "<<*b<<" "<<c<<endl;
*b=9;
cout<<*a<<" "<<*b<<" "<<c<<endl;
int num=666;
const int *ptr_num=const_cast<const int *>(&num);
cout<<*ptr_num<<" "<<num<<endl;
num=999;
cout<<*ptr_num<<" "<<num<<endl;
return 0;
}
输出结果:
四、重新解释转换(reinterpret_cast)
重新解释转换用于将一个指针转换为其他类型的指针,该类型转换危险程度极高,容易造成未定义的行为。
reinterpret_cast支持基本类型指针之间的转换
也支持上下行类型之间的转换包括不相关的类类型之间的转换
#include <iostream>
using namespace std;
class A
{
public:
int a=1;
int b=2;
int c=3;
};
class B:public A
{
public:
int d=4;
int e=5;
int f=6;
};
class C
{
public:
int g=7;
int h=8;
int i=9;
};
int main()
{
//用指针实例化一个类对象
A *ptr_a=new A();
B *ptr_b=new B();
C *ptr_c=new C();
cout<<"A的数据:"<<ptr_a->a<<endl<<"B的数据:"<<ptr_b->d<<endl<<"C的数据:"<<ptr_c->g<<endl;;
//A指向B,B指向A,C指向A,A指向C,B指向C,C指向B
A *ptr_a1=reinterpret_cast<A *>(new B());
B *ptr_b1=reinterpret_cast<B *>(new A());
C *ptr_c1=reinterpret_cast<C *>(new A());
A *ptr_a2=reinterpret_cast<A *>(new C());
B *ptr_b2=reinterpret_cast<B *>(new C());
C *ptr_c2=reinterpret_cast<C *>(new B());
cout<<"A指针访问数据:"<<ptr_a1->a<<" "<<ptr_a2->c<<endl<<"B指针访问数据:"<<ptr_b1->f<<" "<<ptr_b2->a<<endl<<"C指针访问的数据:"<<ptr_c1->g<<" "<<ptr_c2->i<<endl;
return 0;
}
运行结果:
ps:通过运行结果可知,数据访问乱了!
其他
上下行转换关系图
(父类与子类关系可以理解为基类与派生类关系)
其余类型转换方法
类型转换方法其实远不止四个,比如自动类型转换(系统会自动转换)
规则:占用内存字节数少的类型向占用内存字节数多的类型转换(内存字节数可以用值域替代),目的保证精度不降。
编写程序证明有符号类型自动转换为无符号类型(最终输出结果为无符号类型)
ps2:强制类型转换
(强制转换的类型)(被转换的表达式)
编写程序自证类型发生了强制转换