新型的注释
C++添加了一种新型的注释,它以双斜杠(//)开头,在一行的结尾处结束:
/*这是一条C和C++中的注释,在此结束->*/
int five= 2+2;//这是一条C++中的注释,在本行结尾处结束->
新的注释类型很短小,仅有一行的注释(如变量声明)是最为有用的。旧注释类型在注释内容超过一行是仍然是需要的。个人的喜好决定了你何时使用哪种类型的注释。
struct、enum、和union的名字是类型名
在C中,你必须在结构名之前加上关键字stuct。例如,在下面的例子中,我们必须写struct FooTag:
/*ccode*/
StructFooTag {
Struct FooTag* next; /*keyword “struct” required*/
/*…*/
};
StructFooTag myfool; /*here too*/
FooTagmyfoo2; /*error:forgot “struct” */
对next和myfool的声明是正确的,而在myfool2前则需要添加关键字struct。在C++中,一旦你声明了一个结构名,就不必再重复关键字struct了。
//C++code
StructBar {
//structtag Bar is declared at this point
Bar* next; //you need’t precede struct tag Bar with keyword // “struct”
//…
};
Struct Bar mybar1; //you can still write “struct Bar”
Bar mybar2; //but you don’t need to
这里,即使Bar是一个结构名,我们也可以使用它来声明next
和mybar2而无须使用关键字struct, 对mybar1的声明可以说明你仍旧可以使用关键字struct, 如果你喜欢这样做的话。
对于enum, 上面的规则仍然适用:
enum Color {RED, WHITE, BLUE};
enum Color background; /*in C we’d have to write this*/
Color foreground; //in C++ we can (and do) write this
对于union应该:
UnionToken_value{
int ival;
double dval;
char* sval;
};
union Token_valuetoken1; /*must do this in C*/
Token_valuetoken2; //can dothis in C++
当然, C 程序员通常使用typedef来创建一些较为短小的名字。实际上,一个结构常被定义为typedef 的一部分,以便我们能同时给它一个短小的名字:
Typedefstruct { /* in c, struct definition isusually part of typefef */
Foo* head;
Foo* tail;
}FooQueue;
这里我们并没有给结构命名,只是加了一个typedef。在C++中,这个typedef 就不需要了, 但是省略了它之后,即使是很用经验的程序员也可能会忘记结构定义后的分号:
StructFooQueue { in C++, typedef not needed
Foo *head;
Foo *tail;
} //ß oops: forgot the semicolon afterFooQueue definition
Main (){/**/} // does main() return a FooQueue?
FooQueue的定义需要以分号结束,如果没有分号,看起来就像main()的返回值是这个结构的一个实例。
Iostream:新的I/O 库
像C一样, C++有一个标准的I/O库,称为iostream库。C++之所以不使用C的stdio库有两个原因。其一是像printf()这样的函数不具有类型安全性。对于编译器来说,要判断出你传递给printf()的实例类型有无错误是很困难的。其中,stdio中的函数是不可扩展的。你不能将自己的类型添加到printf()的格式串中。在此后的章节中,我们将向你介绍如何扩展iostream库来输出你自己的类型,现在我们仍把重点放在内建类型上。
Iostream库最为显著的特性是它使用移位运算符来代替标准的函数调用。例如,前面的程序可以装换成如下的形式:
#include<iostream.h>
main()
{
cout << “hello, world\n”;
}
它的输出如下:
hello,world
要编写一个标准输出语句,你需要使用一个名为cout的变量(是在iostream的头文件中声明的)和左移位运算符。当左移位运算符做输出用时,我们称它为输出运算符。这个语法是暗示你把数据传递给了cout。它是你用到的第一个有关运算符重载的实例,也是C++的一个新特性,它允许你在将运算符用于自己的类型时给予运算符特定的含义。在本例中,iostream库的创建者已经重载了”<<”运算符,以便输出之用。
用这种方法,你可以输出任何内建类型的值:
cout<< 22.0 / 7.0 //printsa double
cout<< ‘X’ //printsa char
cout<< (5&6); //printsan int
在最后一例中使用了括号,因为”<<”比”&”的优先级高。运算符重载并不改变运算符的优先级,只是改变了它们的运算对象的类型。
Char* 是指向一个以null结束的字符串的指针。当输出char*类型时,将显示出它所指向的字符串,而输出其他的指针时,输出的则是它指向的地址:
char* s =“a fool, a tool, a pool: loopalootaloofa”;
cout<< s; //printsthe string
cout<< (void* )s; //printsthe address of the string
你可以在一个语句中输出多个值,代码如下:
cout<< “the sum of” << 3 << ”and” << 4 << ”is”<< 3+4 << ’n’;
它的输出结构即:
the sumof 3 and 4 is 7
iostream 库提供了cerr来输出标准错误。它的用法和cout一样,但是对输出并不进行缓存。接下来的函数输出的是它的参数的平方根,但是当参数是负值时,它则输出一个标准的错误:
voidprint_sqrt (double d) {
if (d>=0) cout << ”sqrt: ”<< sqrt(d) << ‘\n’;
else cerr << “negative numberpassed\n”;
尽管iostream库的输出语法是它最为显著的特性,但这仅仅是它的牛刀小试。它是一个即灵活又复杂的库,你可以找到许多详细介绍它的C++书。参考书目中有一本书专门介绍它。
注: 在真正打印字符之前,先在缓存中把字符积聚在一起,由此可以缓存提高输出速度。Cerr并不适用缓存,这样调试输出的消息会立刻显示出来。顺便提一下,在cerr和cout这些变量名中的字母c代表character(字符)。你可以将iostream库看作是对象和字符流之间的装换工具。
在这里我们并不深入介绍有关它的太多特性,特别是,我们不打算告诉你如何格式化输出,如何读取输入数据以及如何执行文件和内存缓存的I/O操作等。如果在学习我们的子集时,你需要用到这些特性,就使用C的I/O库,它们在C++中仍然适用。
如果你想在同一个程序中使用两个库,必须调用一个特殊的iostream函数:
#include<stdio.h> //CI/O library header
#include<iostream.h> //C++ I/O library header
main ()
{
Ios::sync_with_stdio(); //call this function so iostream works with stdio
cout<< “now use iostream\n”;
printf (“andstdio\n”);
}
这个函数式ios::sync_with_stdio(), 它允许你随意混合这两个库。