C++ primer plus 第17 章 输入、使用cout进行输出

avatar
作者
筋斗云
阅读量:0

C++ primer plus 第17 章 输入、使用cout进行输出

C++ primer plus 第17 章 输入、使用cout进行输出

文章目录


17.2 使用cout进行输出

正如前面指出的,C++将输出看作字节流(根据实现和平台的不同,可能是8位、16位或32位的字节,但都是字节),但在程序中,很多数据被组织成比字节更大的单位。例如,int类型由16位或32位的二进制值表示;double值由64位的二进制数据表示。但在将字节流发送给屏幕时,希望每个字节表示一个字符值。也就是说,要在屏幕上显示数字-2.34,需要将5个字符(-、2、.、3和4),而不是这个值的 64位内部浮点表示发送到屏幕上。因此,ostream类最重要的任务之一是将数值类型(如int或foat)转换为以文本形式表示的字符流。也就是说,ostream类将数据内部表示(二进制位模式)转换为由字符字节组成的输出流(以后会有仿生移植物,使得能够直接翻译二进制数据。我们把这种开发作为一个练习,留给您)。为执行这些转换任务,ostrcam类提供了多个类方法。现在就来看看它们,总结本书使用的方法,并介绍能够更精密地控制输出外观的其他方法。
17.2.1 重载的<<运算符
本书常结合使用cout和<<运算符(插入(insertion)运算符):

int clients22; cout << clients; 

在 C++中,与℃一样,<<运算符的默认含义是按位左移运算符(参见附录E)。表达式 x<<3 的意思,将x的二进制表示中所有的位向左移动3位。显然,这与输出的关系不大。但ostream 类重新定义了<<运算符,方法是将其重载为输出。在这种情况下,<<叫作插入运算符,而不是左移运算符(左移运算符由于其外观(像向左流动的信息流)而获得这种新角色)。插入运算符被重载,使之能够识别C++中所有的基本类型:

  • unsigned char:

  • signed char;

  • char:

  • short;

  • unsigned short;

  • int;

  • unsiged int;

  • long;

  • unsigned long;

  • long long(C++11);

  • unsigned long long(C++11);

  • foat:

  • double:

  • long double.

  • 对于上述每种数据类型,ostream 类都提供了operator<<()函数的定义(第 11章讨论过,名称中包含运算符的函数用于重载该运算符)。因此,如果使用下面这样一条语句,而value 是前面列出的类型之一,则C++程序将其对应于有相应的特征标的运算符函数:

Cout << value; 

例如,表达式 cout<<88对应于下面的方法原型:

ostream & operator<<(int); 

该原型表明,operator<<()函数接受一个int 参数,这与上述语句中的 88匹配。该原型还表明,函数返回一个指向 ostream 对象的引用,这使得可以将输出连接起来,如下所示:

cout <"I'm feeling sedimental over " << boundary << "\n"; 

如果您是C语言程序员,深受%类型说明符过多、说明符类型与值不匹配时将发生问题等痛苦,则使用cout非常简单(当然,由于有cin,C++输入也非常简单)

1.输出和指针

ostream 类还为下面的指针类型定义了插入运算符函数:

const signed char*; const unsigned char * ; const char *: void* 

不要忘了,C++用指向字符串存储位置的指针来表示字符串。指针的形式可以是char数组名、显式的char指针或用引号括起的字符串。因此,下面所有的cout语句都显示字符串:

char name[20]="Dudly Diddlemore"; char *pn ="Violet D'Amore"; cout << "Hello!"; cout << name; cout << pn; 

方法使用字符串中的终止空字符来确定何时停止显示字符。
对于其他类型的指针,C++将其对应于void*,并打印地址的数值表示。如果要获得字符串的地址,则必须将其强制转换为其他类型,如下面的代码片段所示:

int eggs =12; char *amount :"dozen"; cout << &eggs; cout << amount; cout <<(void*)amount; // prints address of eggs variable //prints the string "dozen" //prints the address of the dozen" string 

2.拼接输出

插入运算符的所有化身的返回类型都是ostrcam&。也就是说,原型的格式如下:

ostream & operator<<(type); 

(其中,type 是要显示的数据的类型)返回类型 ostream&意味着使用该运算符将返回一个指向ostream对象的引用。哪个对象呢?函数定义指出,引用将指向用于调用该运算符的对象。换句话说,运算符函数的返回值为调用运算符的对象。例如,cout<<“potluck”返回的是cout 对象。这种特性使得能够通过插入来连接输出。例如,请看下面的语句:

cout << "We have "<< count << " unhatched chickens.\n"; 

表达式 cout<<“Wehave”将显示字符串,并返回cout 对象。至此,上述语句将变为:

cout <scount <"unhatched chickens.\n"; 

表达式 cout<<count 将显示 count变量的值,并返回cout。然后 cout 将处理语句中的最后一个参数(参见图17.4)。这种设计技术确实是一项很好的特性,这也是前几章中重载<<运算符的示例模仿了这种技术的原因所在。
在这里插入图片描述

17.2.2 其他 ostream 方法

除了各种 operator<<()函数外,ostrcam 类还提供了put()方法和 write()方法,前者用于显示字符,后者用于显示字符串。
最初,put()方法的原型如下:

ostream & put(char); 

当前标准与此相同,但被模板化,以适用于wchart。可以用类方法表示法来调用它:

cout .put('W');//display the w character 

其中,cout 是调用方法的对象,put()是类成员函数。和<<运算符函数一样,该函数也返回一个指向调用对象的引用,因此可以用它将拼接输出:

cout.put('I').put('t');//displaying It with two put()cal1s 

函数调用 cout.put(!')返回 cout,cout 然后被用作 put(‘t’)调用的调用对象。
第17章 输入、输出和文件
739
在原型合适的情况下,可以将数值型参数(如int)用于put(),让函数原型自动将参数转换为正确char值。例如,可以这样做:

cout.put(65);// display the A charactercout.put(66.3);//display the B character 

第一条语句将 int 值 65 转换为一个 char 值,然后显示 ASCI 码为 65 的字符。同样,第二条语句将 double值66.3转换为char值66,并显示对应的字符。
这种行为在 C++2.0之前可派上用场。在这些版本中,C++语言用int 值表示字符常量。因此,下面的语句将"W"解释为一个int值,因此将其作为整数87(即该字符的ASCII值)显示出来:

cout << 'W'; 

然而,下面这条语句能够正常工作:
cout .put(W");因为当前的C++将char 常量表示为char 类型,因此现在可以使用上述任何一种方法。-些老式编译器错误地为 char、unsigned char和 signed char3种参数类型重载了put( )。这使得将 int参数用于 put()时具有二义性,因为int可被转换为这3种类型中的任何一种。
write()方法显示整个字符串,其模板原型如下:

basic ostreamccharT,traits>k write(const char type* s, streamsize n); 

write( )的第一个参数提供了要显示的字符串的地址,第二个参数指出要显示多少个字符。使用 cout 调用write()时,将调用 char 具体化,因此返回类型为 ostream &。程序清单 17.1演示了 write()方法是如何工作的。

程序清单 17.1 write.cpp

// write.cpp -- using cout.write() #include <iostream> #include <cstring>  // or else string.h  int main() {     using std::cout;     using std::endl;     const char * state1 = "Florida";     const char * state2 = "Kansas";     const char * state3 = "Euphoria";     int len = std::strlen(state2);     cout << "Increasing loop index:\n";     int i;     for (i = 1; i <= len; i++)     {         cout.write(state2,i);         cout << endl;     }  // concatenate output     cout << "Decreasing loop index:\n";     for (i = len; i > 0; i--)         cout.write(state2,i) << endl;  // exceed string length     cout << "Exceeding string length:\n";     cout.write(state2, len + 5) << endl;     // std::cin.get();     return 0;  }  

注意,cout.write()调用返回cout 对象。这是因为 write()方法返回一个指向调用它的对象的引用,这里调用它的对象是 cout。
这使得可以将输出拼接起来,因为cout.write()将被其返回值 cout 替换:

cout.write(state2,i)<< endl; 

还需要注意的是,wite()方法并不会在遇到空字符时自动停止打印字符,而只是打印指定数目的字符,即使超出了字符串的边界!在这个例子中,在字符串“kansas”的前后声明了另外两个字符串,以便相邻的内存包含数据。编译器在内存中存储数据的顺序以及调整内存的方式各不相同。例如,“Kansas”占用6个字节,而该编译器使用4个字节的倍数调整字符串,因此“Kansas”被填充成占用8个字节。由于编译器之间的差别,因此输出的最后一行可能不同。
write()方法也可用于数值数据,您可以将数字的地址强制转换为char*,然后传递给它:

long val:560031841:cout.write((char*)&val,sizeof(long)); 

这不会将数字转换为相应的字符,而是传输内存中存储的位表示。例如,4字节的long值(如 560031841)将作为4个独立的字节被传输。输出设备(如显示器)将把每个字节作为ASCI码进行解释。因此在屏幕上,560031841将被显示为4个字符的组合,这很可能是乱码(也可能不是,请试试看)。然而,write()确实为将数值数据存储在文件中提供了一种简洁、准确的方式,这将在本章后面进行介绍。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!