类型转换
- 隐式类型转换
- C语言风格的强制类型转换
- 对于char short int 类型之间的转换,是通过改变指针类型来实现,
- 对于浮点类型float、double
- 对类进行强制类型转换
- 类 向上转型 向下转型
- 静态类型转换static_cast
- 动态强制转换 dynamic_cast
提要:
将派生类对象转换为基类对象(向上转型)
将基类对象转换为派生类对象(向下转型)
补充说明,
这里的对象可以是引用或者指针,一般情况下,向上转型是一种安全行为。
向下转型时,
如果对象定义时是基类,却要转型为派生类,就不被允许
允许的情况是,
比如我定义了一个派生类T的对象,把它转型为基类B的对象。
这时候把这个基类B的对象转型成派生类T的对象就是可以的。
隐式类型转换
常见于算数运算,比如int+float,int会先隐式转换为float再进行加法;
数字转char字符的技巧:
char a = 5
将一位数字转为char类型,上式结果并不是字符’5’
因为按照ascll编码表,‘5’对应的位置是53,
想要得到’5’,
可以再加上字符’0’
char a = ‘0’ +5
对于类来说:
隐式类型转换 允许 向上转型
不允许 向下转型
因为向下转型风险不可控、比如越界访问;
C语言风格的强制类型转换
语法就是,在被转换的变量前写上,要转向的数据类型,用小括号括起来。
浅显的理解(x86下):
对于char short int 类型之间的转换,是通过改变指针类型来实现,
举个例子:
unsigned int a{ 0x00123010 };
unsigned char q1{ (unsigned char)a };
unsigned short w1{ (unsigned short)a };
std::cout <<std::hex<<"q1=" << (int)q1 << std::endl
std::cout <<"w1=" << w1 << std::endl;
输出 q1=10 w1=3010
由此可见,把4字节的int类型转换为 1字节的char、2字节的short类型时,
会出现内存切片的情况;
从汇编的视角来看,其实只是在传递值的时候,更改了指针的类型来实现了强制转换;
unsigned int a{ 0x00123010 };
00A37656 mov dword ptr [a],123010h
unsigned char q1{ (unsigned char)a };
00A3765D mov al,byte ptr [a]
00A37660 mov byte ptr [q1],al
unsigned short w1{ (unsigned short)a };
00A37663 mov ax,word ptr [a]
00A37667 mov word ptr [w1],ax
对于浮点类型float、double
x86有专们用来进行类型转换的汇编指令
cvtsi2ss 和 cvtsi2sd
分别对应32位单精度float 和 64位双精度double
对类进行强制类型转换
根据类继承时的规则,基类的成员变量会先放到内存中,
举个例子,写一个只有int类型的成员变量的类,
然后将类对象 强制转换为int*类型;
就可以通过指针偏移来访问每一个成员变量
class T
{
public:
int a{ 100 }, b{ 101 }, c{ 102 };
};
class T1 :public T
{
public:
int d{ 103 };
};
int main()
{
T1 t1;
int* ptr = (int*)&t1;
std::cout << ptr[0] << std::endl;
std::cout << ptr[1] << std::endl;
std::cout << ptr[2] << std::endl;
std::cout << ptr[3] << std::endl;
}
输出: 100 101 102 103
类 向上转型 向下转型
//只看变量不看函数的情况
向上转型:将派生类对象 转型为基类
向上转型时,比如基类中有成员变量共占12字节,派生类的成员变量占4字节;由于通过基类指针只能访问基类的成员变量,那么就不会出现 访问超过目标对象的内存范围 的情况;
向下转型时:将基类对象 转型为派生类
向下转型时,通过派生类指针要访问属于派生类的成员变量,就属于非法访问了;因为目标对象是基类,根本就没有创建派生的成员变量,这时候访问,得到的就是一个未知的数;
如上述的例子:
T t;
T1* t1 = (T1*) & t;
std::cout << t1->d;
我的运行结果是:-858993460 ,并不是103
所以向下类型转换,是有风险的;
静态类型转换static_cast
static类型转换在编译时,会检查转换合不合法,不合法就报错;
比如:
我想把类对象的引用 转换成int*类型,用强制类型转换可以,用static类型转换就不行;
动态强制转换 dynamic_cast
用dynamic_cast可以在对象多态中安全的进行类型转换
dynamic_cast只能用于支持方法多态类型的指针,如果转换成功,返回指针,转换失败,返回nullptr
一般在两种情况中要使用dynamic_cast
1》向下转换downcast
2》跨类转换crosscast
注意点:
1》不要转换this指针
2》当dynamic_cast用于转换引用时,转换失败会抛出异常,所以也不推荐转换引用