每周100个C++知识点(备忘录)(七)

001-038 异常

1.一般的try-throw-catch块,首先通过try调用函数,函数中间定义了throw块,负责抛出错误,输出出现错误的提示信息,进一步转入catch块,catch块将对异常进行处理。注意,throw抛出的异常,与catch接收的参数是同类型的

2.抛出的异常类型,可以是字符串或其他C++类型,但通常为类类型。执行throw相当于执行返回语句,终止函数执行,但它不是将控制权返回给调用程序,而是导致程序沿函数调用序列后退,直到try块;如果有catch,则将控制权返回给main(),程序将在main()中寻找异常处理程序catch

3.catch块类似于一个函数定义,但不是函数定义,关键字catch表示这是一个处理程序,参数列表表明该处理程序与throw块抛出的异常相匹配

4.执行完try块中的语句后,如果没有引发任何异常,则跳过try后的catch块,直接执行处理程序后面的第一条语句

5.如果函数引发了异常,而没有try块或没有匹配的处理程序时,在默认的情况下,程序最终将调用abort()函数,但是可以修改这种行为

6.通常,引发异常的函数将传递一个对象,这样做的优点是,可以使用不同的异常类型来区分不同的函数在不同的情况下引发的异常。同时,对象可以携带信息,程序员可以根据这些信息来确定引发异常的原有,catch块根据这些信息来决定采取什么样的措施

7.对于返回异常是对象的函数(throw语句),catch的参数是该对象的引用,且在catch中去使用该对象的方法,来向外传递错误信息。也就是说,可以定义一个类,在catch中初始化一个对象,将这个对象作为catch的参数,再在catch语句块内调用方法

8.异常规范是一种比较老且褒贬不一的特殊方法,在C++11中可以使用noexcept关键字指出函数不会引发异常,也可以使用运算符noexcept()判断其操作数是否会引发异常,这相当于编写函数的程序员做出了承诺

9.栈解退:假设try快没有直接调用引发异常的函数,而是调用了对引发异常的函数进行调用的函数,则程序流程将从引发异常的函数跳到包含try块和处理程序的函数

10.C++通常通过将信息放在栈中来处理函数调用,即程序将调用函数的指令的地址(返回地址)放到栈中,当被调用的函数执行完毕后,程序将使用该地址来确定从哪里开始继续执行。另外,函数调用将函数参数放在栈中,在栈中,这些函数参数被视为自动变量。如果被调用的函数创建了新的自动变量,则这些变量也被添加到栈中;如果被调用的函数调用了另一个函数,则后者的信息将被添加到栈中

11.当函数结束时,程序流程将跳到该函数被调用时存储的地址处,同时栈顶的元素被释放,因此,函数通常都返回到调用它的函数,同时每个函数都在结束时释放其自动变量。如果自动变量是对象,则类的析构函数将被调用

12.假设函数由于出现异常(而不是返回)而终止,则程序也将释放栈中的内存,但不会在释放栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于try块中的返回地址。随后,控制权将转到块尾的异常处理程序,而不是调用函数后的第一条语句,这个过程被称为栈解退

13.引发栈解退机制的一个重要特性:像函数返回一样,对于栈中的自动类对象,类的析构函数将被调用,然而函数返回仅仅处理该函数放在栈中的对象,而throw语句则处理try块和throw之间整个函数调用序列放在栈中的对象,如果没有这种特性,则引发异常后,对于中间函数调用放在栈中的自动类对象,不会调用析构函数

14.对于函数中嵌套的函数,如果被包含的函数返回了一个throw信息,则外部函数接收到这个信息,而后将其再次抛出,即重新引发一个异常,将由下一个捕获这种异常的try-catch块进行处理,如果没有这样的处理程序,默认情况下程序异常终止

15.throw-catch机制类似于函数参数和函数返回机制,但区别在于:①函数将控制权返回调用该函数的地方(函数),但throw语句将控制权向上返回到第一个包含能够捕获相应异常的try-catch组合,且这个组合可能在上上层函数中;②引发异常时编译器总是创建一个临时拷贝,即使异常规范和catch块中指定的是引用,因为原函数中的对象在函数执行完将不存在

16.既然throw语句生成副本,为何代码中使用引用呢?因为基类引用可以执行派生类对象,假设有一组通过继承关系关联起来的异常类型,则在异常规范中只需列出一个基类引用,它将与任何派生类对象匹配(此处使用引用不是为了因减少创建副本而提高效率)

17.对于异常类层次结构,分别处理不同的异常类型,则使用基类引用可以捕获任何异常对象;而使用派生类对象只能捕获它所属类及从这个类派生而来的类的对象。引发的异常对象将被第一个与之匹配的catch块捕获,及catch块的排列顺序应该与派生顺序相反

18.如果有一个异常类继承层次结构,应该这样排列catch块:将捕获位于层次结构最下面的异常类的catch语句放在最前面,将捕获基类异常的catch语句放在最后面

19.当不知道函数会发生什么异常时,如使用一个函数调用另一个未知函数时,可以使用省略号来表示异常类型,从而捕获任何异常。如果知道一些可能会引发的异常,可以将捕获所有异常的catch块放在最后面,类似于switch语句中的default。思路是:catch时先小后大

20.exception类:C++编译器将异常合并到语言中,exception头文件定义了exception类,C++可以把它作为其他异常类的基类,代码可以引发exception异常,也可以将exception类作为基类。其中有一个明为what()的虚成员函数,它返回一个字符串,该字符串的特征随现实而异,并且它是虚方法,可以在从exception派生而来的类中重新定义它

21.如果不想以不同的方式处理由exception派生而来的异常,可以在同一个基类处理程序中捕获它们,即catch(std::exception & e),再执行其他语句

22.stdexcept异常类:头文件stdexcept定义了其他几个异常类:logic_error和runtime_error类,它们都是以公有方式从exception派生而来的。这些类的构造函数接受一个string对象作为参数,该参数提供了方法what()以C-风格字符串方式返回的字符数据。logic_error和runtime_error被用作两个系列的基类

23.logic_error描述典型逻辑错误,通过合理的编程可以避免这些错误,但实际上还是很容易发生的。它派生了以下类,每个类的名称指出了它用于报告的错误类型:①domain_error(定义域异常);②invalid_argument(传递意外值异常);③length_error(没有足够空间执行操作异常);④out_of_bounds(指示索引错误)

24.runtime_error描述可能在运行期间发生但难以预计和防范的错误:①range_error(值域错误);②overflow_error和underflow_error(上下溢错误,浮点计算中,存在浮点类型可以表示的最小非零值,计算结果比这个值还小时发生下溢错误;计算结果超过了某种类型表示范围时发生上溢错误)

25.一般而言,logic_error系列异常表面存在可以通过编程修复的问题,而runtime_error系列异常表明存在无法避免的问题。这些错误有共同特征,区别在于:不同类名能够分别处理不同异常;继承关系能够一起处理异常

26.如果以上方法不可以满足对异常的需求,可以从logic_error或runtime_error派生一个异常类,以确保异常类可以归入同一个继承层次结构中

27.bad_alloc异常:对于使用new导致的内存分配问题,C++的处理方式是让new引发bad_alloc异常,头文件new包含了bad_alloc类的声明,它从exception类公有派生而来

28.老版new的异常是返回空指针,C++标准提供了一种在失败时返回空指针的new,用法是:type * name = new (std::nothrow) type或type * name = new (std::nothrow) type[]

29.异常、类和继承相互关联,可以通过:①类似标准C++库,从一个异常类派生出另一个;②可以在类定义中嵌套异常类声明来组合异常;③嵌套声明本身可以被继承,还可以用作基类

30.异常被引发后,在两种情况下会导致问题:①如果它是在带异常规范的函数中引发的,则必须与规范列表中的某种异常匹配(在继承层次结构中,类类型与这个类及其派生类的对象匹配),否则称为意外异常;②如果异常不是在函数中引发的(或者函数没有异常规范),则必须捕获它,如果没有捕获(在没有try块或没有匹配的catch块时),则异常被称为未捕获异常

31.未捕获异常通常不会导致程序立刻异常终止,程序将首先调用函数terminate(),在默认情况下,terminate()函数调用abort()函数,可以指定terminate()调用的函数来修改terminate()的行为,为此可调用set_terminate()函数,它和terminate()都定义在exception头文件中

32.如果调用了set_terminate()函数多次,则terminate()将调用最后一次set_terminate()调用设置的函数。该函数的定义是void set_terminate(void f),因此调用函数是一个void类的函数

33.原则上,异常规范应包含函数调用的其他函数引发的异常,但这样太过复杂了。如果函数引发了其异常规范中没有的异常,机制也很复杂。在这种情况下,行为与未捕获的异常相似,如果发生意外异常,程序将调用unexpected()函数,它将调用terminate()函数,后者默认情况下调用abort()函数

34.与set_terminate()相似,也有一个set_unexpected()函数,它和unexpected()函数也是在exception头文件中定义。同样,它的语法也是void set_unexpected(void f)

35.set_unexpected()函数的行为受到更多限制,它可以:①通过调用terminate()、abort()或exit()来终止程序;②引发异常

36.引发异常的结果取决于函数所引发的异常以及引发意外异常的函数的异常规范:①如果新引发的异常与原来的异常规范匹配,则程序将从那里开始进行正常处理,即寻找与新引发的异常匹配的catch块;②如果新引发的异常与原来的异常规范不匹配,且异常规范中没有包括std::bad_exception类型,则程序将调用terminate(),bad_exception从exception派生而来,位于头文件exception中;③如果新引发的异常与原来的异常规范不匹配,且原来的异常规范中包含了std::bad_exception类,则不匹配的异常将被std::bad_exception异常所取代

37.要捕获所有的异常(预期的、意外的),可以:①确保异常头文件声明可用(exception)、名称空间std;②设计一个替代函数,将意外异常转换为bad_exception异常,原型是:void myUnexpected() {throw std::bad_exception();};③在程序开始位置,将意外异常操作指定为调用该函数:set_unexpected(myUnexpected);④将bad_exception类型包括在异常规范中,添加catch块序列,其中原函数的异常规范抛出常规错误和意外错误对象

38.异常规范不适用于模板,因为模板函数引发的异常可能随特定的具体化而异,异常和动态内存分配不总能协调工作。解决办法是使用C++11的新的“智能指针模板”

039-049 运行阶段类型识别,RTTI

39.RTTI是运行阶段类型识别(Runtime Type Identification)的简称,这是新添加到C++中的特性之一,它旨在为程序在运行阶段确定对象的类型提供一种新的标准方式

40.假设定义了一个基类,而很多个派生类都是从同一个基类中派生而来的,在使用时可用将基类指针指向其中任何一个类的对象,如何知道指针指向的是哪种对象,RTTI提供了解决以下两个问题的方案:①派生类对象可能包含不是继承而来的方法,在这种情况下,只有某些类型的对象可用使用该方法;②处于调试的目的,像跟踪生成的对象的类型

41.RTTI的工作原理,C++有3个支持RTTI的元素:①如果可能的话,dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针,否则返回空指针;②typeid运算符返回一个指出对象类型的值;③type_info结构存储了有关特定类型的信息

42.★★★★★★RTTI只适用于包含虚函数的类。因为只有虚函数确保将多种指针中的任何一种指向最终派生类对象时,都可以调用最终类的方法

43.dynamic_cast运算符回答“是否可用安全地将对象的地址赋给特定类型的指针”的问题(不回答“指针指向哪类对象”),其语法是derived_class * dc = dynamic_cast<derived_class * >(bc),其中bc是一个基类对象。这个语句指出:指针bc的类型是否可用被安全地转换为派生类指针?如果可用,则返回对象地址,否则返回空指针

44.如果指向对象(* dc)的类型为bc或从bc直接或间接派生而来的类型,则表达式dynamic_cast< bc * >(dc)将指针dc转换为bc类型,否则为空指针

45.应尽可能地使用虚函数,而只在必要时使用RTTI。也可以将dynamic_cast用于引用,但没有与空指针对应的引用值,因此无法使用特殊的引用值来指示失败。当请求不正确时,dynamic_cast引发类型为bad_cast的异常,它是从exception类派生而来,在头文件typeinfo中定义

46.typeid运算符使得能够确定两个对象是否为同种类型,它和sizeof有点像,可以接受两种参数:①类名;②结果为对象的表达式。typeid运算符返回一个对type_info对象的引用,其中,type_info是在头文件typeinfo中定义的一个类,重载了==和!=运算符,以便可以使用运算符来对类型进行比较

47.如果pg指向一个Magnificent对象,则下列表达式:typeid(Magnificent)==typeid(*pg)的结果为bool值true,否则为false。如果pg是一个空指针,则将引发bad_typeid异常,该异常在typeinfo中声明,从exception类派生而来

48.type_info类的实现随厂商而异,但包含一个name()成员,该函数返回一个随实现而异的字符串,通常是类的名称。typeid测试用来选择一种操作,因为操作不说类的方法,所以不能通过类指针调用它

49.RTTI争议比较大,有的时候使用的代价也比较大。如果发现在扩展的if else语句系列中使用了typeid,则应考虑是否应该使用虚函数和dynamic_cast

050-054 类型转换运算符

50.C的通用类型转换,在进行转换时可能并没有意义,或存在不严格的松散状况,C++提供了更严格的类型转换,添加了4个类型转换运算符,使转换过程更规范:①dynamic_cast;②const_cast;③static_cast;④reinterpret_cast

51.dynamic_cast:当且仅当Low是High的可访问基类(直接或间接)时,语句pl=dynamic_cast< Low * > ph;才将Low * 指针赋给pl,否则,该语句将空指针赋给pl,通用语法是:dynamic_cast < type-name > (expression),该运算符的用途是使得能够在类层次结构中进行向上转换,而不允许其他转换

52.const_cast:用于执行只有一种用途的类型转换,即改变值为const或volatile,语法与dynamic_cast相同:const_cast < type-name > (expression),如果类型的其他方面也被修改,则上述类型转换将出错,意味着除了const或volatile特征可以不同外,其他的(type_name和expression)类型必须相同。该运算符的用途是,有时候需要一个在大多数情况是常量,而有时是可修改量,在此时将该量声明为const,且在需要修改的时候使用const_cast

53.static_cast:语法与前两个相同,static_cast < type-name > (expression),仅当type_name可被隐式转换为expression所属的类或expression可隐式转换为type-name所属类型时,上述转换才合法,否则将出错。由于无需进行类型转换,枚举值就可以被转换为整型,所以可以用static_cast将整型转换为枚举值

54.reinterpret_cast:用于天生危险的类型转换,不允许删除const,但执行其他令人烦躁的任务,这个运算符用于比较底层的技术,不可移植

055-070 C++输入输出概述

55.用于文件输入和输出的C++工具都是基于cin(istream类对象)和cout(ostream类对象)所基于的基本类定义

56.一些语言将输入输出(如print)当作关键字,输入输出本身就包含在语言中(如Python、BASIC),但C和C++的关键字不包括与I/O有关的内容,C最初把I/O留给了编译器实现任意,这样是为了让实现人员能够自由设计I/O函数,使之最适合于目标计算机的硬件要求

57.多数实现人员把I/O建立在最初为UNIX环境开发的库函数的基础上,C++也支持这个软件包,需要使用cstdio来支持这些函数(C的stdio.h)

58.C++依赖于C++的I/O解决方案,而不是C语言的I/O解决方案,前者是在头文件iostream和fstream中定义一组类,这个类库不说正式语言定义的组成部分(cin和istream不说关键字)。C++也自带了一个标准类库,它是一个非正式的标准,只是由头文件iostream和fstream中定义的类组成

59.C++程序把输入和输出看作字节流,输入时,程序从输入流中抽取字节,输出时,程序将字节插入到输出流中。对于面向文本的程序,每个字节代表一个字符。更通俗地说,字节可用构成字符或数值数据的二进制表示

60.输入流中的字节可能来自键盘,也可能来自存储设备(硬盘)或其他程序,输出流中的字节可用流向屏幕、打印机、存储设备或其他程序。流充当了程序和流源或流目标之间的桥梁,使得C++程序可以以相同的方式对待来自键盘的输入和来自文件的输入

61.C++程序只是检查字节流,而不需要知道字节来自何方。通过使用流,C++程序处理输出的方式将独立于其去向,因此管理输入包含两步:①将流与输入去向的程序关联起来;②将流与文件连接起来

62.输入流需要两个连接,每端各一个,文件端连接提供了流的来源,程序端连接将流的流出部分转储到程序中(文件端可用是文件、设备);对输出的管理包括将输出流连接到程序以及将输出目标与流关联起来

63.高效地处理输入和输出,使用的是缓冲区。缓冲区是用作中介的内存块,它是将信息从设备传输到程序或从程序传输给设备的临时存储工具。程序通常每次只能处理一个字节的信息,缓冲区帮助匹配硬件设备和程序处理的信息传输速率

64.从磁盘上读取信息非常慢,但可用将磁盘的信息放在缓冲区中,然后每次从缓冲区里读取一个字节,这种方法更快、方便。缓冲区读取结束后,将再从磁盘上读取另一块数据;输出时,程序先填满缓冲区,然后把整块数据传输给硬盘,并清空缓冲区,以备下一批使用,这个操作被称为刷新缓冲区

65.键盘输入每次提供一个字符,这种清空下不需要缓冲区匹配信息传输速率,但对键盘输入进行缓冲可以让用户在将输入传输给程序之前返回并更正。C++程序通常在用户按下回车时刷新缓冲区;对于屏幕输出,通常在用户发送换行符时刷新输出缓冲区

66.管理流和缓冲区的类:①基类ios类,一般流属性,包括一个指向streambuf对象的指针;②streambuf类,管理输入/输出缓冲区的内容;③ostream类,输出方法;④istream类,输入方法;⑤iostream类,从istream类和ostream类继承了输入和输出方法

67.ios_base类表示流的一般特征,如是否可读取、是二进制流还是文本流等,输出格式的内容也在此定义;ios类基于ios_base,其中包括了一个指向streambuf对象的指针成员

68.创建cout(ostream对象)处理输出时,将打开一个流,自动创建缓冲区,并将其与流关联起来,同时使得能够使用类成员函数

69.C++的iostream类库管理了很多细节,在程序中包含iostream文件将自动创建8个流对象(4个用于窄字符流,4个用于宽字符流):①cin与wcin,处理标准输入流与宽输入流;②cout与wcout,处理标准输出流和宽输出流;③cerr与wcerr,与标准错误流相对应,可用于现实错误信息,这个流没有被缓冲,意味着信息直接发送给屏幕;④clog与wclog,对应标准错误流,但这个流被缓冲

70.对象代表流:声明一个iostream对象时,该对象将包含存储与输入/输出信息有关的信息的数据成员,如字段宽度、小数位数、现实整数时采用的计数方法以及描述用来处理输出流的缓冲区的streambuf对象的地址

071-081 使用cout进行输出

71.ostream类最重要的任务之一是将数值类型转换为以文本形式表示的字符流,也就是将数据内部表示(二进制位模式)转换为由字符字节组成的输出流

72.<<运算符的本身含义是按位左移运算符,在ostream类重新定义了该运算符,将其重载为输出。此时,<<叫做插入运算符。插入运算符被重载,使得可以处理C++所有的基本类型

73.<<重载的函数原型是,ostream & operator<< (type);,表明该函数返回一个指向ostream对象的引用,这使得可用将输出连接起来

74.除了基本类型,ostream类还为以下指针类型定义了插入运算符函数:①const signed char * ;②const unsigned char * ;③const char * ,这样可用让字符数组、字符串指针、直接的字符串被cout打印,方法使用字符串中的终止空字符来确定何时停止显示字符;④void * ,可用将它用作强制转换,返回指向变量的地址

75.ostream类还提供了put()方法,用于显示字符;write()方法,用于显示字符串。put()的原型是:ostream & put(char);(当前定义为模板),由于返回类型,因此可用拼接输出,可以将数值类型参数用于put(),让函数原型自动将参数转换为正确char值(ASCII字符);write()的原型是:basic_ostream< char T,traits> & write(const char_type * s, streamsize n);,第一个参数提供要显示字符串的地址,第二个参数指出要显示多少个字符,调用时,将调用char具体化,因此返回类型为ostream &

76.write()方法不会在遇到空字符时自动停止打印字符,而是打印指定数目的字符,即使超出字符串边界,可能打印内存前后的字符。write()方法也可用于数据数值,可以将数字的地址强制转换为char * ,然后传递给write(),这样不会讲数字转换为相应的字符,而是传输内存中存储的位表示(很可能是乱码)

77.刷新输出缓冲区:标准输出连接到文件时,使用缓冲区可以节省大量时间,但标准输出使用cout时,会在输入即将发生时刷新缓冲区,也就是立刻显示cout的消息,即使没有换行符。如果实现不能在希望时刷新输出,可以使用flush刷新缓冲区,或使用endl刷新缓冲区并换行

78.flush控制符也是函数,因此可以直接调用flush来刷新cout缓冲区,语法是flush(cout),但ostream类对<<使用flush进行了重载,使得可以使用cout<< flush

79.ostream插入运算符讲值转换为文本格式,在默认情况下,格式化值的方法为:①对于char,如果它代表可打印字符,则将被作为一个字符显示在宽度为一个字符的字段中;②对于整数类型,将以十进制方式显示在一个刚好容纳该数字及符号的字段中;③字符串被显示在宽度等于该字符串长度的字段中

80.浮点数的默认行为:浮点类型被显示为6位,末尾的0不显示(显示的数字位数与数字被存储时精度没有关系),数字以定点表示法显示还是科学计数法显示取决于它们的值。当指数大于等于6或小于等于-5时,将用科学计数法显示,字段宽度恰好容纳数字和符号

81.因为每个值的显示宽度都等于它的长度,因此必须显式地在值之间提供空格,否则相邻的值将不会被分开。末尾不带0的浮点数值后面将有6个空格

082-100 cout输出格式控制

82.修改显示时使用的计数系统:ios_base类存储了描述格式状态的信息,由于ios_base是ostream类的间接基类,因此可以将其方法用于ostream对象。ios_base类中的成员和方法以前位于ios类中,现在ios_base类是ios类的基类,后者包含char和wchar_t具体化模板,前者包含非模板特性

83.设置显示整数时使用的技术系统:①十六进制:hex(cout);,或写为(通常写为):cout<<hex;,这是因为ostream类重载了<<运算符,使得上述方法等价;②八进制:oct(cout);或cout<<oct;;③十进制:dec(cout);或cout<<dec;。注意控制符不是成员函数,不必通过对象来调用。程序将使用该计数系统打印数字,直到下一次格式状态设置的更改

84.调整字段宽度:数字字段的宽度不相同时,可以使用width成员函数将长度不同的数字放到宽度相同的字段中,方法的原型是:int width();或int width(int i);,第一种格式返回字段宽度的当前设置,第二种格式将字段宽度设置为i个空格,并返回以前的字段宽度值,这样可以保存之前的字段宽度值。width()方法只影响将显示的下一个项目,然后字段宽度将恢复为默认值

85.对于被设置宽度的输出,字符将被放到最右边,这被称为右对齐,是默认行为。★★★★★width()方法只影响接下来显示的一个项目,然后字段宽度将恢复为默认值(原始默认值为0)

86.C++不会截短数据,如果试图在宽度为2的字段中打印一个7位值,C++将增宽字段,容纳该数据。C++的原则是,显示所有的数据比保持列的整洁更重要

87.填充字符:默认情况下,cout用空格填充字段中未被使用的部分,可以用fill()成员函数来改变填充字符,语法是:cout.fill(’* ');,将使用* 填充字符。与字段宽度设置不同的是,新的填充字符一直有效,直到更改

88.设置浮点数的显示精度:浮点数精度的含义取决于输出模式,默认模式下,它指的是显示的总位数。在定点模式和科学模式下,精度指的是小数点后面的位数。C++的默认精度是6位,末尾的0不显示,precision()成员函数能够选择其他值,例如cout.precision(2);将cout的精度设置为2,和width()不同,新的精度设置将一直有效,直到下一次被设置

89.打印末尾的0和小数点:iostream系列类没有提供专门的函数,但ios_base类提供了一个setf()函数,能控制多种格式化特性,它定义了多个常量,可用作该函数的参数。语句cout.setf(ios_base::showpoint);显示末尾小数点,使用默认浮点格式时,末尾的0将被显示出来。showpoint是ios_base类定义的一个类级静态常量,在类外使用需要加上作用域运算符

90.setf()的其他控制:setf()方法控制了小数点被显示时其他几个格式选项,ios_base类有一个受保护的数据成员,其中的各位(标记)分别控制着格式化的各个方面(计数系统、是否显示末尾的0等),打开一个标记称为设置标记(或位),意味着相应的位被设置位1

91.setf()函数有两个原型,第一个为fmtflags setf(fmtflags);,其中,fmtflags是bitmask类型的typedef名,用于存储格式标记,该名称在ios_base中定义。这个版本的setf()用来设置单个控制位的格式信息,参数是一个fmtflags值,指出要设置哪一类,返回值是类型为fmtflags的数字,指出所有标记以前的设置,如果打算以后恢复原始设置,则可以保存这个值

92.setf()中的ios_base类定义代表位值的常量:①ios_base::boolalpha,输入和输出bool值,可为true或false;②ios_base::showbase,对于输出,使用C++基数前缀(0,0x);③ios_base::showpoint(),显示末尾的小数点;④ios_base::uppercase,对于16进制输出,使用大写字母,E表示法;⑤ios_base::showpos,在正数前面加上+

93.bitmask类型是一种用来存储各个位值的类型,它可以是整型、枚举,也可以是STL bitset容器,主要思想是,每一位都是可以单独访问的,都有自己的含义,iostream软件包使用bitmask来存储状态信息

94.setf()的第二个函数原型接受两个参数,并返回以前的设置:fmtflags setf(fmtflags , fmtflags);,第一参数和以前一样,也是一个包含了所需设置的fmtflags值,第二参数指出要清除第一参数中的哪些位。具体原理涉及位,ios_base定义了表示位的常量

95.setf(ios_base::expr1, ios_base::expr2);的组合为:①第二参数为ios_base::basefield,第一参数为ios_base::dec(基数10),ios_base::oct(基数8),ios_base::hex(基数16);②第二参数为ios_base::floatfield,第一参数为ios_base::fixed(定点计数法),ios_base::scientific(科学计数法);③第二参数为ios_base::adjustfield,第一参数为ios_base::left(左对齐),ios_base::right(右对齐),ios_base::internal(符号或基数前缀左对齐,值右对齐)

96.在C++标准中,定点表示法和科学表示法都有2个特征:①精度指的是小数位数,而不是总位数;②显示末尾的0。setf()函数是ios_base类的一个成员函数,由于这个类是ostream类的基类,因此可以用cout对象来调用该函数,如语句ios_base::fmtflags old = cout.setf(ios_base::left, ios::adjustfield);,恢复以前的设置可以用cout.setf(old, ios_base::adjustfield)

97.调用setf()的效果可以通过unsetf()消除,后者的原型为:void unsetf(fmtflags mask);,其中,mask是位模式,mask中的所有位都设置为1,将使得对应的位被复位,也就是setf()设置为1,unsetf()设置为0

98.没有专门指示浮点数默认显示模式的标记,仅当只有定点位被设置时使用定点表示法,仅当只有科学位被设置时使用科学表示法,其他组合,如果没有位被设置或两位都被设置时,使用默认模式。默认模式的启用方法之一是:cout.setf(0, ios_base::floatfield);,另一种是cout.unsetf(ios_base::floatfield);

99.使用setf()不是进行格式化最方便的方法,C++提供多个控制符可以调用setf(),自动提供正确的参数,即可以这样调用:cout<< left << fixed;,其他的有:①boolalpha/noboolalpha;②showbase/noshowbase;③showpoint/noshowpoint;④showpos/noshowpos;⑤uppercase/nouppercase;⑥(开始对应2参数,其一为adjustfield)internal/left/right;⑦(开始对应2参数,其一为basefield)dec/hex/oct;⑧(开始对应2参数,其一为floatfield)fixed/scientific

100.头文件iomanip也提供格式化控制符,其中setprecision()接受指定精度的整数参数;setfill()接受一个指定填充字符的char参数;③setw()接受一个指定字段宽度的整数参数,它们都可以和cout连接起来使用

这几天抓紧把输入输出和文件输入输出学了,C++更新可能相对就慢了,要把精力放在PCL上,开始做实战!希望一切快快好起来

下期预告:输入、文件、内核格式化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值