当前位置:首页 » 《随便一记》 » 正文

C++之数据类型转换(全)

19 人参与  2023年04月01日 19:05  分类 : 《随便一记》  评论

点击全文阅读


文章目录

自动类型转换string与“万物”互转const char *与“万物”互转char* 与”万物“互转char[]与int,float,double互转int,float,double互转char与intstatic_castdynamic_castconst_castreinterpret_cast总结
当我们用C++编写代码时,经常会遇到数据类型的转换,如string,char*,char[],const char*、Qstring以及int,float等各种类型之间的转换。

而且有些转换的函数在低版本的C++中是不支持的,所幸这里我们对C++中常用的数据类型转换进行记录。

在数据转换中,尤其是字符串转换是最常用的,所以我们以字符串来作为整个数据类型转换的核心。


自动类型转换

这里分为两种情况:

当不同类型的变量同时运算时就会发生数据类型的自动转换。

char 和 int 两个类型的变量相加时,就会把 char 先转换成 int 再进行加法运算如果是 int 和 double 类型进行运算时,就会把 int 转换成 double 再进行运算。条件判断中,非布尔型自动转换为布尔类型。

用一个参数作为另一个不同类型参数的赋值时出现的自动转换。

当定义参数是char,输入是int时,自动将int通过ASCII转换为字符当定义参数是int,输入是浮点型,自动转换为浮点型。

string与“万物”互转

string与const char*

//string 转 const char*string a = “niaho”;const char* b = a.c_str();  //赋值//const char*转stringstring c = b;   //赋值string(b)   //强转

string与char*

//string 转 char*string a = “nihao”;char* c = const_cast<char*>(a.c_str());char* d =  (char*)a.c_str();  //采用char*强转//char* 转 stringstring(c);  //强转string a = c; //赋值

string与char[]

//string 转 char[]char a[] = "nihao";string c = "oahin";//string 转 char[]//方法一for(int i=0; i<strlen(a); i++) a[i] = c[i];//方法二strcpy_s(a, c.c_str());  //调用函数//char[] 转 stringstring b = a;  //赋值string(a)   //强转

strcpy_s是微软库的函数,如果不是vs系列的编译器,可以使用strcpy,但要注意栈溢出问题。

string与int、float、double

//string 转 int,long,doublestring a = "3.14"//方法一cout << atoi(c.c_str()) << endl;cout << atol(c.c_str()) << endl;cout << atof(c.c_str()) << endl;  //方法二template<class T>T StrToNum(const string& str){    istringstream iss(str);    T num;    iss>>num;    return num;}//int,float,double 转 stringfloat a = 3.14;//方法一to_string(a);  //结果   3.140000//方法二template<class T>string NumToStr(T& num){    ostringstream oss;    oss<<num;    string str(oss.str());    return str;}

这里需要提醒的是atoi函数在不同的编译器上对于溢出问题的返回是不一样的,需要注意。

to_string是C++11的标准,如果你使用的老版本C++,比如蓝桥杯比赛,是不支持to_string的。

方法二采用泛型编程的好处可以降低代码冗余而实现更多的功能。

const char *与“万物”互转

const char*与char*

//const char* 转 char*const char* a = “nihao”;char* c = const_cast<char*>(a);char* d =  (char*)a;  //采用char*强转//char* 转 const char*const char* f = d;  //直接赋值即可cout<< (const char*)d << endl; //强转

const char*与char[]

//const char* 转 char[]char a[100];const char* s = "nihao";strcpy_s(a, s);cout<< a << endl;//char[] 转 const char*const char *s = a;  //赋值

这里采用strcpy_s而不是strcpy,是因为strcpy_s操作更加的安全,不过需要采用vs code胡总和vs studio等微软的编译器才可以使用。

如果采用dev等编译器,则直接使用strcpy即可,不过需要自己注意数组溢出问题。

const char*与int, float, double

//cosnt char* 转 int,long,doubleconst char* a = "3.14"//方法一cout << atoi(a) << endl;cout << atol(a) << endl;cout << atof(a) << endl;  //方法二template<class T>T StrToNum(const char* &str){    istringstream iss(str);    T num;    iss>>num;    return num;}//int,float,double 转 const char*float a = 3.14;//方法一to_string(a).c_str();  //结果   3.140000//方法二template<class T>const char* NumToStr(T& num){    ostringstream oss;    oss<<num;    const char* str = oss.str();    return str;}

char* 与”万物“互转

char*与char[]

//char* 转 char[]char a[100];char* s = "nihao";strcpy_s(a, s);cout<< a << endl;//char[] 转 char*const char *s = a;  //赋值

char*与int, float, double

//char* 转 int,long,doublechar* a = "3.14"//方法一cout << atoi(a) << endl;cout << atol(a) << endl;cout << atof(a) << endl;  //方法二template<class T>T StrToNum(char* &str){    istringstream iss(str);    T num;    iss>>num;    return num;}//int,float,double 转 char*float a = 3.14;//方法一char* c = const_cast<char*>(to_string(a).c_str());//方法二template<class T>char* NumToStr(T& num){    ostringstream oss;    oss<<num;    char* str = oss.str();    return str;}

const只是一个常量修饰符,所以char*的很多转换操作是类似的。

其中int,float,double转char*的方法一纯纯有点傻了。

char[]与int,float,double互转

char[]与int,float,double

//char[] 转 int,long,doublechar a[] = "3.14"//方法一cout << atoi(a) << endl;cout << atol(a) << endl;cout << atof(a) << endl; //int,long,double转 char[]int a = 3;char s[100] = {0};strcpy_s(s, to_string(a).c_str());

int,float,double互转

隐式转换规则:当需求参数是int,而传入参数是float时,就会发生隐式转换,所以这里我们要注意的就是在函数重载的时候,因为隐式转换,导致编译不能有效识别部分函数。

float a = 3.14;int b = a;cout << b << endl;cout << int(b) << endl;  //强转

char与int

常通过ASCII表,实现字符数字与int数字之间的转换
//char 转 intchar a = '1';int b = a-'0';cout << b << endl;//int 转 charint c = 1;char d = c + '0';cout << d << endl;

上面所有的转换都是侧重于讲数据类型的"值"原封不动的转换为其他类型,而接下来的4种数据类型转换函数,则更加侧重于数据”类型“的转换。

static_cast

这个关键字的作用主要表现在 static 上,是一种静态的转换,在编译期就能确定的转换,可以完成C语言中的强制类型转换中的大部分工作,但需要注意的是,它不能转换掉表达式的 constvolitale 或者 __unaligned 属性。

{ //int 转 charint a = 124;    char c = static_cast<char>(a);    cout << c << endl;}{  //找回存放在void*指针中的值    int *a = new(int);    *a = 96;    void* b = static_cast<void*>(a);    char* c = static_cast<char*>(b);    cout << c << endl;}{ //用于父类指针   struct B { };   struct D : B { };   D d;   B& rb = d;   D& rd = static_cast<D&>(rb);}
直接讲int转成char数据指针与指针之间的转换,这个时候不能用于两个无关指针类型的直接转换,需要通过void*进行间接转换。父类指针转成子类指针,这是安全的,反之则是不安全的,因为static_cast是没有动态类型检查的

使用时机

当编译器隐式执行类型转换时,大多数编译器会给出警告

该操作会损失精度!!

而采用static_cast可以明确告诉编译器,这是知情的情况下进行的。

dynamic_cast

只用于类继承结构中基类和派生类之间指针或引用的转换,可以进行向上、向下,或者横向的转换。

相比于 static_cast 的编译时转换, dynamic_cast 的转换还会在运行时进行类型检查,转换的条件也比较苛刻

必须有继承关系的类之间才能转换在基类中有虚函数才可以,有一种特殊的情况就是可以把类指针转换成 void* 类型。
struct B { virtual void test() {} };struct D1 : virtual B { };struct D2 : virtual B { };struct MD : D1, D2 { };D1* pd1 = new MD();std::cout << pd1 << std::endl;// 向上转型B* pb = dynamic_cast<B*>(pd1);std::cout << pb << std::endl;// 向下转型MD* pmd = dynamic_cast<MD*>(pd1);std::cout << pmd << std::endl;// 横向转型D2* pd2 = dynamic_cast<D2*>(pd1);std::cout << pd2 << std::endl;

运行结果如下,在横向转换时指针发生了变化,可以看出 dynamic_cast 不是简单的数据强转,还进行了指针的偏移:

0x10619200x10619200x10619200x1061928

const_cast

const_cast 不能去除变量的常量性,只能用来去除指向常数对象的指针或引用的常量性,且去除常量性的对象必须为指针或引用。

这个我们在上面的例子中就用到了很多次,这里讲一个错误的案例

const int val = 6;//编译错误 //error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]int* cp = &val;

还有就是const_cast使用往往是无奈之举,这里举一个例子,希望认真的阅读

代码1

const int val = 6;std::cout << "&val=" << &val << ", val=" << val << std::endl;const int* cp = &val;int *p = const_cast<int*>(cp);*p = 2;std::cout << "&val=" << &val << ", val=" << val << std::endl;std::cout << "p=" << p << ", *p=" << *p << std::endl;

代码2

int init = 6;const int val = init;……………………

在代码1的最前面加上了int init = 6;

运行结果如下:

&val=0x61fe0c, val=6&val=0x61fe0c, val=6p=0x61fe0c, *p=2    //这里是在编译时,会对其常量值进行替换
&val=0x61fe04, val=6&val=0x61fe04, val=2  //这里编译器替换已经不其作用了,而是直接更改了常量的值p=0x61fe04, *p=2   

如果可以的话,尽可能在程序设计阶段就规避这种情况,不要使用const_cast

reinterpret_cast

不同类型指针或引用之间的转换。指针和整数之间的转换。

是对比特位的简单拷贝并重新解释。

不同基础类型指针类型之间转换

int *p = new int;// 编译失败 //error: invalid static_cast from type ‘int*’ to type ‘char*’char* p1 =  static_cast<char*>(p);// 编译成功char* p2 =  reinterpret_cast<char*>(p1);

将地址转换成整数

struct B { int val;};B b{101};std::cout << "&b=" << &b << std::endl;long addr = reinterpret_cast<long>(&b);std::cout << "addr=" << addr << std::endl;

运行结果如下:

&b=0x7ffffdc4f270addr=140737450930800

总结

综上所述,前面的数据类型”值“的转换才是本次的关键,后4个关键字我们发现大多和指针,类指针,继承甚至多态有关,这里我们重点关注数据类型之间的转换。


老规矩,有问提问,有用三连,感谢!


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/57877.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1