Oracle Solaris Studio 12.2:C++ 用户指南

13.7 操纵符

操纵符是可以在 iostream 中插入或提取以起到特殊作用的值。

参数化操纵符是具有一个或多个参数的操纵符。

因为操纵符是普通的标识符,因此会用完可能的名称,而 iostream 不会为每个可能的函数定义操纵符。本章的其他部分讨论了各种操纵符和成员函数。

有 13 个预定义的操纵符,如表 13–2 中所述。使用该表时,要进行以下假设:

表 13–2 iostream 的预定义操纵符

 

预定义的操纵符  

说明  

ostr << dec、istr >> dec

以 10 为基数进行整数转换。

ostr << endl

插入一个换行符 (’\n’) 并调用 ostream::flush()

ostr << ends

插入一个空 (0) 字符。这在处理 strstream 时很有用。

ostr << flush

调用 ostream::flush()

ostr << hex、istr >> hex

以 16 为基数进行整数转换。

ostr << oct、istr >> oct

以 8 为基数进行整数转换。

istr >> ws

提取空白字符(跳过空白),直至找到非空白字符(留在 istr 中)。

ostr << setbase(n)、istr >> setbase(n)

将转换基数设置为 n(仅限 0、8、10、16)。

ostr << setw(n)、istr >> setw(n)

调用 ios::width(n)。将字段宽度设置为 n。

10 

ostr << resetiosflags(i)、istr >> resetiosflags(i) 

根据 i 中设置的位,清除标志位向量。

11 

ostr << setiosflags(i)、istr >> setiosflags(i)

根据 i 中设置的位,设置标志位向量。

12 

ostr << setfill(c)、istr >> setfill(c)

将填充字符(用来填充字段)设置为 c

13 

ostr << setprecision(n)、istr >> setprecision(n)

将浮点精度设置为 n 位数。

要使用预定义的操纵符,必须在程序中包含文件 iomanip.h

您可以定义自己的操纵符。操纵符共有两个基本类型:

13.7.1 使用无格式操纵符

无格式操纵符是具有如下功能的函数:

由于为 iostream 预定义了采用(指向)此类函数(的指针)的移位运算符,因此可以在输入或输出运算符序列中放入函数。移位运算符会调用函数而不是尝试读取或写入值。例如,下面是将 tab 插入 ostreamtab 操纵符:


ostream& tab(ostream& os) {
             return os <<’\t’;
            }
...
cout << x << tab << y;

详细描述实现以下操作的方法:


const char tab = ’\t’;
...
cout << x << tab << y;

下面示例显示了无法用简单常量来实现的代码。假设要对输入流打开或关闭空白跳过功能。可以分别调用 ios::setfios::unsetf 来打开和关闭 skipws 标志,也可以定义两个操纵符。


#include <iostream.h>
#include <iomanip.h>
istream& skipon(istream &is) {
       is.setf(ios::skipws, ios::skipws);
       return is;
}
istream& skipoff(istream& is) {
       is.unsetf(ios::skipws);
       return is;
}
...
int main ()
{
      int x,y;
      cin >> skipon >> x >> skipoff >> y;
      return 1;
}

13.7.2 参数化操纵符

iomanip.h 中包含的其中一个参数化操纵符是 setfillsetfill 设置用于填写字段宽度的字符。该操作按照下例所示实现:


//file setfill.cc
#include<iostream.h>
#include<iomanip.h>

//the private manipulator
static ios& sfill(ios& i, int f) {
         i.fill(f);
         return i;
}
//the public applicator
smanip_int setfill(int f) {
       return smanip_int(sfill, f);
}

参数化操纵符的实现分为两部分:

头文件 iomanip.h 中定义了多个类。每个类都保存一个操纵符函数的地址和一个参数的值。manip(3CC4) 手册页中介绍了 iomanip 类。上面的示例使用了 smanip_int 类,它是与 ios 一起使用。因为该类与 ios 一起使用,所以也可以与 istreamostream 一起使用。上面的示例还使用了另一个类型为 int 的参数。

applicator 创建并返回类对象。在上面的代码示例中,类对象是 smanip_int,其中包含了操纵符和 applicator 的 int 参数。iomanip.h 头文件定义了用于该类的移位运算符。如果 applicator 函数 setfill 在输入或输出操作序列中,会调用该 applicator 函数,且其返回一个类。移位运算符作用于该类,以使用其参数值(存储在类中)调用操纵符函数。

在以下示例中,操纵符 print_hex

使用类 omanip_long 的原因是该代码示例仅用于输出,而且操作对象是 long 而不是 int


#include <iostream.h>
#include <iomanip.h>
static ostream& xfield(ostream& os, long v) {
        long save = os.setf(ios::hex, ios::basefield);
        os << v;
        os.setf(save, ios::basefield);
        return os;
    }
omanip_long print_hex(long v) {
       return omanip_long(xfield, v);
   }