【C++高阶(九)】C++类型转换以及IO流

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

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


【C++高阶(九)】C++类型转换以及IO流,C++从入门到精通,c++,IO流,类型转换

1. 前言

C语言中常见的类型转换有隐式类型
转换和强制转换,但是在面向对象的
语言中,这样使用未免太不优雅了!

本章重点:

本篇文章前半截着重讲解C++强制
转换的四种类型,以及为什么C++
需要自己设计一套类型转换.其中
会复习C语言的类型转换的方式.
后半截会讲解C++的IO流和文件IO
还会介绍string stream相关知识


2. C语言类型转换的方式

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。

  1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
int i = 1;
// 隐式类型转换
double d = i;
printf("%d, %.2f\n" , i, d);
  1. 显式类型转化:需要用户自己处理
int* p = &i;
// 显示的强制类型转换
int address = (int) p;
printf("%x, %d\n" , p, address);

C语言类型转换的缺陷:

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰

因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。


3. C++的强制类型转换

标准C++为了加强类型转换的可视性
引入了四种命名的强制类型转换操作符:

static_cast

reinterpret_cast

const_cast

dynamic_cast

下面将一一介绍它们的用法:

  1. static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换

double d = 12.34;
int a = static_cast<int>(d);//将d强制转换为int类型
cout<< a <<endl;
  1. reinterpret_cast

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
// 这里使用static_cast会报错,应该使用reinterpret_cast
//int *p = static_cast<int*>(a);
int *p = reinterpret_cast<int*>(a);
  1. const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

const int a = 2;
int* p = const_cast<int*>(&a);
*p = 3;
cout << a << endl;
cout << *p << endl;

请注意,当你去测试这段代码时,确实不会报错,但是打印出来a的结果是2而不是3,*p的结果是3,这是因为当a被赋予const属性后,操作系统内部会做优化,每次使用a时会直接去寄存器中取,而不是去内存中取,显然,内存中的a已经被修改了!

【C++高阶(九)】C++类型转换以及IO流,C++从入门到精通,c++,IO流,类型转换

  1. dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用

  • 向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
  • 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

注意:

  1. dynamic_cast只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
class A
{
public :
	virtual void f(){}
};
class B : public A
{};

void fun (A* pa)
{
	// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
	B* pb1 = static_cast<B*>(pa);
	B* pb2 = dynamic_cast<B*>(pa);
	cout<<"pb1:" <<pb1<< endl;
	cout<<"pb2:" <<pb2<< endl;
}
int main ()
{
	A a;
	B b;
	fun(&a);
	fun(&b);
	return 0;
}

用dynamic_cast转换只是安全的
并不代表一定能转换成功!


4. RTTI介绍(了解)

RTTI:Run-time Type identification
即:运行时类型识别

C++通过以下方式来支持RTTI:
1. typeid运算符
2. dynamic_cast运算符
3. decltype

这三种方式我们都学过了,RTTI
属于了解内容


5. C语言的输入输出和缓冲区

C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来进行输入与输出。如下图所示:

【C++高阶(九)】C++类型转换以及IO流,C++从入门到精通,c++,IO流,类型转换

由于输入输出缓冲区是Linux系统
要学习的内容,所以这里就简单讲解

对输入输出缓冲区的理解:

  1. 可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植的程序。
  2. 可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,只有文件满了才会刷新,缓冲区的存在可以让用户有更好的体验,也就是行刷新

6. C++IO流

C++系统实现了一个庞大的类库
其中ios为基类
其他类都是直接或间接派生自ios类
【C++高阶(九)】C++类型转换以及IO流,C++从入门到精通,c++,IO流,类型转换

C++标准库提供了4个全局流对象cin、cout、cerr、clog,使用cout进行标准输出,即数据从内存流向控制台(显示器)。使用cin进行标准输入即数据通过键盘输入到程序中,同时C++标准库还提供了cerr用来进行标准错误的输出,以及clog进行日志的输出,从上图可以看出,cout、cerr、clog是ostream类的三个不同的对象,因此这三个对象现在基本没有区别,只是应用场景不同。

  1. cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
  2. 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置位(置1),程序继续。
  3. 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格。回车符也无法读入。
  4. cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了
  5. 对于自定义类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载。

7. C++文件IO流

C++根据文件内容的数据格式分为二进制文件和文本文件。采用文件流对象操作文件的一般步骤:

  1. 定义一个文件流对象
    ifstream ifile(只输入用)
    ofstream ofile(只输出用)
    fstream iofile(既输入又输出用)
  2. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
  3. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
  4. 关闭文件
struct ServerInfo
{
	char _address[32];
	int _port;
	Date _date;	
};
struct ConfigManager
{
public:
ConfigManager(const char* filename)
	:_filename(filename)
{}
void WriteBin(const ServerInfo& info)
{
	ofstream ofs(_filename, ios_base::out | ios_base::binary);
	ofs.write((const char*)&info, sizeof(info));
}
void ReadBin(ServerInfo& info)
{
	ifstream ifs(_filename, ios_base::in | ios_base::binary);
	ifs.read((char*)&info, sizeof(info));
}
    // C++文件流的优势就是可以对内置类型和自定义类型,都使用
    // 一样的方式,去流插入和流提取数据
    // 当然这里自定义类型Date需要重载>> 和 <<
    // istream& operator >> (istream& in, Date& d)
      // ostream& operator << (ostream& out, const Date& d)
void WriteText(const ServerInfo& info)
{
	ofstream ofs(_filename);
	ofs << info._address << " " << info._port<< " "<<info._date;
}
void ReadText(ServerInfo& info)
{
	ifstream ifs(_filename);
	ifs >> info._address >> info._port>>info._date;
}
private:
	string _filename; // 配置文件
};
int main()
{
	ServerInfo winfo = { "192.0.0.1", 80, { 2022, 4, 10 } };
	// 二进制读写
	ConfigManager cf_bin("test.bin");
	cf_bin.WriteBin(winfo);
	ServerInfo rbinfo;
	cf_bin.ReadBin(rbinfo);
	cout << rbinfo._address << " " << rbinfo._port <<" "
	<<rbinfo._date << endl;
	// 文本读写
	ConfigManager cf_text("test.text");
	cf_text.WriteText(winfo);
	ServerInfo rtinfo;
	cf_text.ReadText(rtinfo);
	cout << rtinfo._address << " " << rtinfo._port << " " <<
	rtinfo._date << endl;
	return 0;
}

8. 总结以及拓展

本篇文章的内容不属于面试常考点,
但是了解了总比不了解号,没准面试官
问的偏,你这时就赢麻了(狗头)

拓展:

string stream的相关概念:

string stream介绍文章来源地址https://www.toymoban.com/news/detail-761624.html


🔎 下期预告:C++11线程库🔍

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

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

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

相关文章

  • 爬虫高阶攻略:从入门到精通!

    引言:作为一名程序员,想必大家都有了解过爬虫的基本原理,也写过一些简单的爬虫程序。但要想成为爬虫高手,需要更深入的学习和实践。本文将带领大家探究爬虫高阶技巧,从入门到精通的学习资料,让你成为实战型的爬虫攻略专家! 1. 爬虫反反爬 爬虫反爬是指网站

    2024年02月03日
    浏览(37)
  • Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解

    上个篇章回顾,我们上个章节,讲了Redis中的快表(QuickList),它是一种特殊的数据结构,用于存储一系列的连续节点,每个节点可以是一个整数或一个字节数组。快表是Redis中的底层数据结构之一,常用于存储有序集合(Sorted Set)等数据类型的底层实现。 那么本章讲解Red

    2024年02月09日
    浏览(50)
  • Redis从入门到精通【高阶篇】之底层数据结构跳表(SkipList)

    上个篇章回顾,我们上个章节我们学习了《Redis从入门到精通【高阶篇】之底层数据结构整数集(IntSet)详解》,我们从源码层了解整数集由一个头部和多个数据块组成。头部中存储了整数集的元素个数、编码方式和数据块的起始地址等信息。数据块中存储了实际的整型数据,当

    2024年02月09日
    浏览(47)
  • Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解

    前面的Redis从入门到精通的基础篇和进阶篇都是在使用层面和概念层面,本章节,我们了解一下redis的底层数据结构,上几个章节,我们讲了SDS,字典 。本章节我们聊一下ZipList。 压缩列表(ZipList)就是redis为了节约内存而设计开发的数据结构,并且作为列表键和哈希键的底层

    2024年02月08日
    浏览(87)
  • Redis从入门到精通【高阶篇】之底层数据结构整数集(IntSet)详解

    上个篇章回顾,我们上个章节我们学习了《Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解》,我们从源码层了解字典是一种以键值对(key-value)形式存储数据的数据结构。在 Redis 中,字典使用哈希表来实现。哈希表是一种以常数时间复杂度 O(1) 进行插入、删

    2024年02月09日
    浏览(40)
  • 【036】读懂C++的强制类型转换static_cast、const_cast、dynamic_cast以及reinterpret_cast

    💡 作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。 👉 🎖️ CSDN实力新星,社区专家博主 👉 🔔 专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、

    2024年02月12日
    浏览(37)
  • Ceph入门到精通-bluestore IO流程及导入导出

    bluestore 直接管理裸设备,实现在用户态下使用linux aio直接对裸设备进行I/O操作 写IO流程: 一个I/O在bluestore里经历了多个线程和队列才最终完成,对于非WAL的写,比如对齐写、写到新的blob里等,I/O先写到块设备上,然后元数据提交到rocksdb并sync了,才返回客户端写完成(在S

    2024年02月07日
    浏览(34)
  • 关于C或C++,数组的强制类型转换,uint8_t与char的区别,uint8_t*与char*的兼容性问题以及一些指针的常见问题

    1.类型定义: uint8_t:这是一个无符号 8 位整数类型,定义在 stdint.h 或 inttypes.h 头文件中。它是标准的固定宽度整数类型之一,确保在所有平台上占用 8 位(1 字节)。 char:这是 C 语言的基本字符存储类型,用于存储单个字符。在不同的系统和编译器中,char 可以是有符号的

    2024年01月24日
    浏览(36)
  • JavaScript基础:js介绍、变量、数据类型以及类型转换

      目录 介绍 引入方式 内部方式 外部形式 注释和结束符 单行注释 多行注释 结束符 输入和输出 输出 输入 变量 声明 赋值 变量名命名规则 常量 数据类型 数值类型 字符串类型 布尔类型 undefined 类型转换 隐式转换 显式转换 Number 📖引入方式 JavaScript 程序不能独立运行

    2024年04月27日
    浏览(43)
  • 『C++』C++的类型转换

    「前言」 文章是关于C++特殊类型转换 「归属专栏」 C嘎嘎 「笔者」 枫叶先生(fy) 「座右铭」 前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 有些事不是看到了希望才去坚持, 而是因为坚持才会看到希望。 ——《十宗罪》 目录 一、C语言中的类型转换 二、为什么

    2024年02月04日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包