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

这篇具有很好参考价值的文章主要介绍了C++之数据类型转换(全)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


当我们用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*转string
string 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* 转 string
string(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[] 转 string
string b = a;  //赋值
string(a)   //强转

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

string与int、float、double

//string 转 int,long,double
string 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 转 string
float 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,double
const 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,double
char* 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,double
char 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 转 int
char a = '1';
int b = a-'0';
cout << b << endl;

//int 转 char
int c = 1;
char d = c + '0';
cout << d << endl;

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

static_cast

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

{ //int 转 char
	int 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 不是简单的数据强转,还进行了指针的偏移:

0x1061920
0x1061920
0x1061920
0x1061928
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=6
p=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=0x7ffffdc4f270
addr=140737450930800
总结

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


老规矩,有问提问,有用三连,感谢!文章来源地址https://www.toymoban.com/news/detail-780262.html

到了这里,关于C++之数据类型转换(全)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】引用之带你“消除”C语言版数据结构教材的一些困惑(虽然是C++的内容,但是强烈建议正在学习数据结构的同学点进来看看)

    👀樊梓慕: 个人主页  🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 引用的概念 引用的特性 引用的使用场景 引用和指针的区别 C语言版数据结构教材的解惑 不知道

    2024年02月08日
    浏览(36)
  • 数据结构中: 一元多项式的运算(相加,相减,相乘)------用C语言 / C++来实现。 数据结构线性表的操作和应用(顺序存储)

    线性表的操作和应用(顺序存储)。用顺序存储实现一元多项式,并进行加、减、乘运算。 (1)一元多项式结构体创建  (2)初始化 (3)一元多项式赋值             (4)打印一元多项式 (5)加法运算                        (6)减法运算 (7)乘法运算    全部代

    2024年02月01日
    浏览(41)
  • C++之数据类型转换(全)

    当我们用C++编写代码时,经常会遇到数据类型的转换,如string,char*,char[],const char*、Qstring以及int,float等各种类型之间的转换。 而且有些转换的函数在低版本的C++中是不支持的,所幸这里我们对C++中常用的数据类型转换进行记录。 在数据转换中,尤其是字符串转换是最常用

    2024年02月03日
    浏览(25)
  • 【C语言】【数据结构】自定义类型:结构体

    这是一篇对结构体的详细介绍,这篇文章对结构体声明、结构体的自引用、结构体的初始化、结构体的内存分布和对齐规则、库函数offsetof、以及进行内存对齐的原因、如何修改默认对齐数、结构体传参进行介绍和说明。                  ✨  猪巴戒 :个人主页✨      

    2024年02月05日
    浏览(25)
  • 从C语言到C++_37(特殊类设计和C++类型转换)单例模式

    目录 1. 特殊类设计 1.1 不能被拷贝的类 1.2 只能在堆上创建的类 1.3 只能在栈上创建的类 1.4 不能被继承的类 1.5 只能创建一个对象的类(单例模式)(重点) 1.5.1 饿汉模式 1.5.2 懒汉模式 2. 类型转换 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3. RTTI(了解)和类型转换常见面

    2024年02月10日
    浏览(34)
  • C语言自定义数据类型(三)结构体指针

    所谓结构体指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么,这个指针变量就指向该结构体变量。 目录 一、指向结构体变量的指针 1.1举例说明 二、指向结构体数组的指

    2024年02月06日
    浏览(34)
  • C语言自定义数据类型(二)使用结构体数组

    一个结构体变量中可以存放一组有关联的数据(如一个学生的学号、姓名、成绩等数据)。如果有 10 个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组的不同之处在于每个数组元素都是一个结构体类型的数据,它们都分别

    2024年01月19日
    浏览(32)
  • C++数据结构:图结构入门

    线性顺序表(数组) 线性顺序表(链表) Python风格双向链表的实现 散列表简单实现(hash表) 栈和队列的应用 二叉树之一(数组存储) 二叉树之二(二叉搜索树) 二叉树之三(二叉搜索树扩展) 图结构入门 前面系列文章介绍了线性结构和树形结构,线性结构的前驱与后续

    2024年02月07日
    浏览(30)
  • R语言的数据类型与数据结构:向量、列表、矩阵、数据框及操作方法

    R语言拥有丰富的数据类型和数据结构,以满足各类数据处理和分析的需求。本文将分享R语言中的数据类型,包括向量、列表、矩阵、数据框等,以及它们的特点、用途和操作方法。 向量是R语言中最基本的数据结构,它可以存储单个数据类型的元素序列。向量具有固定的长度

    2024年03月11日
    浏览(36)
  • c++基础数据结构

    基础数据结构 目录 • 线性结构 • 二叉堆 • 并查集 • 哈希表 • 应用举例 一、线性结构 基础知识 • 数组 • 带头结点的双链表 – He a d 结点 : 虚拟头结点 – Fir s t 结点 : 第一个有实际内容的结点 • 队列 : 循环队列与 Open-Close 表 例 1. 最小值 • 实现一个 n 个元素的线性

    2024年02月10日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包