谈谈C++的类型转换。

来源:互联网 发布:中石油风险矩阵 编辑:程序博客网 时间:2024/06/05 21:12

   学习C++已经很久了,由于工作原因,很长一段时间没有用了,再加上经常用一些脚本语言,使得对C++的一些概念,反而有些混乱。所以这里我跟大家一起讨论一下C++的类型转换。如文章中有任何纰漏,还请指正。

  众所周知,在PYTHON和其他一些脚本语言中,声明变量是不需要指定类型的。

a=5
b="hello"
   但是在C++中这样声明变量,显然是不能通过编译的。需要指定变量的类型:

int a=5;char b[]="hello"
  如果经常用脚本语言你想要a+b

那么在PYTHON中你直接这样就行了

c=chr(a)+bprint(c)
解释器会自动根据你指定的类型转换函数 ,直接操作并得出结果,下面是PYTHON中的一些类型转换函数:

[python] 

int(x [,base ])         将x转换为一个整数    
long(x [,base ])        将x转换为一个长整数    
float(x )               将x转换到一个浮点数    
complex(real [,imag ])  创建一个复数    
str(x )                 将对象 x 转换为字符串    
repr(x )                将对象 x 转换为表达式字符串    
eval(str )              用来计算在字符串中的有效Python表达式,并返回一个对象    
tuple(s )               将序列 s 转换为一个元组    
list(s )                将序列 s 转换为一个列表    
chr(x )                 将一个整数转换为一个字符    
unichr(x )              将一个整数转换为Unicode字符    
ord(x )                 将一个字符转换为它的整数值    
hex(x )                 将一个整数转换为一个十六进制字符串    
oct(x )                 将一个整数转换为一个八进制字符串   
我们这里主要讨论 C++的类型转换。如果想要让上面C++中声明的两个变量相加。那么我们也会用到类型转换函数:

<span style="white-space:pre"></span>int a = 5;<span style="white-space:pre"></span>char b[] = "hello";<span style="white-space:pre"></span>char c[10];<span style="white-space:pre"></span>_itoa_s(a, c, 10);<span style="white-space:pre"></span>strcat_s(c, b);<span style="white-space:pre"></span>printf("%s", c);

这样看来是相当的复杂了。所以我们还是有必要学习一下C++的类型转换。也是为了方便以后的应用。我们在实际应用中一般很少对对象直接进行类型转换。而且这样也经常是不合法的。

   例如

struct m {int a;char b;};struct r {float a;double b;};void printm(r* c){printf("%f,%f",c->a,c->b) }int main(int argc, char* argv[]){m mystruct;mystruct.a = 5;mystruct.b = 'a';printm(&mystruct);
return 0;
}
编译器会提示不存在用户定义的类型转换。那么我们怎么才能让程序顺利的运行呢。只能用一些类型转换的技巧。

struct m {int a;char b;};struct r {float a;double b;};void printm(r* c){printf("%f,%f", c->a, c->b);}int main(int argc, char* argv[]){m mystruct;mystruct.a = 6;mystruct.b = 'b';LPVOID t = &mystruct;printm((r*)t);system("pause");}
这样就可以顺利的编译通过,虽然打印的值跟自己想要的结果大相径庭。我们这里用到一个概念就是 VOID LPVOID的指针。通过转换指针类型,来强制满足编译器对类型的要求。我们之所以这样做,还是因为C++中的各种数据类型所占的内存空间是不一样的。

16位编译器


char :1个字节
char*(即指针变量): 2个字节
short int : 2个字节
int:  2个字节
unsigned int : 2个字节
float:  4个字节
double:   8个字节
long:   4个字节
long long:  8个字节
unsigned long:  4个字节

32位编译器

char :1个字节
char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器)
short int : 2个字节
int:  4个字节
unsigned int : 4个字节
float:  4个字节
double:   8个字节
long:   4个字节
long long:  8个字节
unsigned long:  4个字节

64位编译器
char :1个字节

char*(即指针变量): 8个字节
short int : 2个字节
int:  4个字节
unsigned int : 4个字节
float:  4个字节
double:   8个字节
long:   8个字节
long long:  8个字节
unsigned long:  8个字节

正是因为如此,所以我们想要直接转换数据类型是行不通的。只能通过一些技巧才能进行转换。尤其是在用户自定义的数据类型中。特别重要。很多时候我们会被各种各样的类型转换弄得晕头转向。下面这段代码说明了为什么指针之间的类型转换会被编译器所接受。

 

struct m {int a;char b;};int main(int argc, char* argv[]){int a = sizeof(int*);int b = sizeof(double*);int c = sizeof(char*);int d = sizeof(m*);
     <span style="font-family: Arial, Helvetica, sans-serif;">       int f = sizeof(LPVOID);</span>
printf("%d,%d,%d,%d,%d",a, b, c, d,f);system("pause");return 0;}
  用好C++的关键除了OOP之外,就是我们能够正确的把一个数据类型传递给函数。有时候我们编写了自己的类/结构体。但是需要传递的函数参数的类型却与我们的大相径庭。如何才能把自己的数据结构正确的传递给函数的参数。决定了我们对C++数据类型的掌握程度。有些时候我们的转换虽然通过了编译器,但是却隐藏了致命的错误,使得程序在发布之后出现各种BUG,因此我觉得这个类型转换真的需要好好的学习,理解。
  

当然我们还需要知道C++中的4种强制类型转换。

1、static_cast
    用法:static_cast (expression)
    该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
    (1)用于类层次结构中基类和派生类之间指针或引用的转换
    进行上行转换(把派生类的指针或引用转换成基类表示)是安全的
    进行下行转换(把基类的指针或引用转换为派生类表示),由于没有动态类型检查,所以是不安全的
    (2)用于基本数据类型之间的转换,如把int转换成char。这种转换的安全也要开发人员来保证
    (3)把空指针转换成目标类型的空指针
    (4)把任何类型的表达式转换为void类型
    注意:static_cast不能转换掉expression的const、volitale或者__unaligned属性。

2、dynamic_cast
    用法:dynamic_cast (expression)
    该运算符把expression转换成type_id类型的对象。type_id必须是类的指针、引用或者void*;
    如果type_id是类指针类型,那么expression也必须是一个指针,如果type_id是一个引用,那么expression也必须是一个引用。
    dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
    在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;

3、reinterpret_cast
    用法:reinterpret_cast (expression)
    
type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
    它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,
    在把该整数转换成原类型的指针,还可以得到原先的指针值)。
    该运算符的用法比较多。
    (static_cast .与. reinterpret_cast比较,见下面 )
    该运算符平台移植性比价差。

4、const_cast
    用法:const_cast (expression)
    该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
    常量指针被转化成非常量指针,并且仍然指向原来的对象;
    常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

    

  为什么都说C++是一个复杂的语言,我觉得不是他的OOP特性,而是这些基于底层的细节导致的。在敏捷型语言快速发展遍地开花的今天。我们要想把C++学好,只能通过不断的反复学习,总结经验才能掌握好它的本质。

0 0