C++笔记(一)
- 文件输入输出
- 函数模板、重载以及函数解析
- 小结
1、ostream的一些小知识
(1)
由继承的特性知道:基类引用可以指向派生类函数,而无需进行强制转换。
则例如,参数类型为ostream &的函数可以接受ostream对象(如cout)
或声明的ofstream 对象作为参数。
(2)open()
1 |
|
其中打开文件方式(mode值)有:
方式 | 含义 |
---|---|
ios::in | 为输入(读)而打开文件 |
ios::out | 为输出(写)而打开文件 |
ios::ate | 初始位置设为文件尾 |
ios::app | 所有输出附加在文件末尾 |
ios::trunc | 如果文件已存在则先删除文件 |
ios::binary | 二进制方式 |
这些方法可以组合使用,以或运算(’|’)的方式连接。
可用方法is_open()检测该文件是否存在
(3)setf()
setf()是ostream和ofstream对象的方法,用于设置格式标志来控制输出形式:
1 |
|
fmtflags即为格式控制符,有:
控制符 | 功能 |
---|---|
oct | 用八进制格式显示数值 |
dec | 用十进制格式显示数值 |
hex | 用十六进制格式显示数值 |
left | 输出调整为左对齐 |
right | 输出调整为右对齐 |
scientific | 用科学记数法显示浮点数 |
fixed | 用正常的记数方式显示浮点数 |
showbase | 输出时显示所有数值的基数 |
showpoint | 显示小数点和额外的0 |
showpos | 在非负数值前显示“+” |
skipws | 当一个流进行读取时,跳过空白字符(spaces,tabs,newlines) |
unitbuf | 在每次插入以后,清空缓存区 |
还有一些未列出,可参考C++ primer plus第17章
然后如果需要将调用的setf()效果消除,可以使用unsetf()函数,简单来说,在位模式里(mask),setf()将位设置为1,而unsetf()函数将位恢复为0。(unsetf()函数中的控制符即上述加前缀no即可)
然后对于setf()函数的第二原型,第一个参数指出要设置哪些位,第二个参数指出要清除哪些位(即相当于unsetf()),下面是一些示例:
1 |
|
注:定点表示法指是用格式123.4来表示浮点值,而不管数字长度如何;科学记数法则指使用格式1.23e04,而不考虑数字长度。
iomanip头文件
通过iostream工具来设置一些格式值(如字段宽度)不太方便,为简化工作,C++在头文件iomanip中提供了其他控制符。其中三个最常用的是:
- setprecision(n): 设置实数的精度为n位。在以一般十进制小数形式输出时,n代表有效数字.
- setfill©: 设置填充字符c,c可以是字符常量或字符变量
- setw(n): 设置字段宽度为n位.
- setbase(n): 设置整数的基数为n(n只能是16,10,8)
示例:
1 |
|
2、函数模板
简介
C++新增特性——函数模板,是通用的函数描述。允许以泛型(而不是具体类型)的方式编写程序,因此有时也被称为通用编程。由于类型是用参数表示的,因此模板特性有时也被称为参数化类型。
例如:
1 |
|
上述函数可对多种数据类型的变量进行交换,需要注意的是,函数模板不能缩短可执行程序,也就是说用于多种类型时,实际上会生成多个函数,它的好处仅在于使得生成多个函数定义更简单可靠。
但是可以看出一个纰漏,编写的模板函数很可能无法处理某些类型。另外,有时候通用化是有意义的,就比如定义一个将两个数相加的模板函数,但是作用于两个结构体是就不行了,但是可能结构体中的成员值相加是有意义的,那么这种情况下,第一种解决方案是允许重载运算符+;第二种解决方案是为特定类型提供具体化的模板定义。下面介绍第二种方法。
显式具体化
可以提供一个具体化函数定义——称为显式具体化(explicit specialization),其中包括所需的代码。当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板。
C++98标准如下:
- 对于给定的函数名,可以有非模板函数、模板函数和显式具体化函数以及它们的重载版本
- 显式具体化的原型和定义应以template<>打头,并通过名称来指出类型
- 具体化优先于常规模板,而非模板函数优先于具体化和常规模板
示例:
1 |
|
有关显式实例化可见C++ primer plus第8章8.5.4节
重载解析
对于函数重载、函数模板和函数模板重载,C++需要采取一个定义良好的策略,来决定为函数调用使用哪一个函数定义,尤其是有多个参数时。这个过程被称之为重载解析(overloading resolution)。
在此不介绍过程是如何进行的(大概就是先找参数数目正确的函数,然后利用一套(也许是)半定量的指标来排序,然后选择最佳匹配)
具体参考顺序如下:
- 完全匹配,但常规函数优先于模板
- 提升转换 (例如,char和shorts自动转换为int,float自动转换为double)
- 标准转换 (例如,int转换为char,long转换为double)
- 用户自定义的转换,如类声明中定义的转换
如果有多个匹配的原型,编译器无法完成重载解析过程;如果没有最佳的可行函数,则编译器会打印生成一条错误信息,该消息可能会使用诸如"ambiguous"(二义性)这样的词语。
小结
- 首先,之前老是有一种错误的观念,即我能搜索或是翻书找到的东西,我便默认为已有的东西,没有再次整理发表的任何意义。但是事实上,我自己在搜索时也会注意文章的发布时间、最近更新等,如果都和我一个观念,那岂不是固步自封了?即使我任何自己的理解也没有附加,但并不妨碍我将其作为2022.3.28的一份有关c++笔记的文章po出来。所以说,不止创造市场上没有的新品能博人眼球,模仿炮制畅销品也能分一杯羹,不能固化思维。
- 其次,之前一直没有想过把书上的东西记录下来,虽然现在这样花了一些时间,不过依然觉得是值得的,这种学习记录式的形式更能加深印象,在某种意义上就是一个项目的创立和实践,现在的总结或是以后的回顾都是复盘。建立博客最本质的目的并非写给别人,而是记录自己。
- C++ primer plus真是大块头,现在一半都没看到,
然而2022已经过了四分之一了,道阻且长啊,想想还有好多坑没有填,又要电工阶段测验了,而且我花在数学物理上的时间可谓屈指可数(笑死,可能还没有英语多)
已经有寄的感觉了……