Archive for 23 4 月, 2010

C++ Primer Chapter8

星期五, 23 4 月, 2010

1、IO对象不可复制或赋值:只有支持复制的元素类型可以存储在vector或其他容器类型里;形参或返回类型也不能为流类型。如果需要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用。

2、IO标准库的条件状态

strm::iostate 机器相关的整形名,由各个iostream类定义,用于定义条件状态

strm::badbit strm::iostate类型的值,用于指出被破坏的流

strm::failbit strm::iostate类型的值,用于指出失败的IO操作

strm::eofbit strm::iostate类型的值,用于指出流已经到达文件结束符

s.eof() 如果设置了流s的eofbit值,则该函数返回true

s.fail() 如果设置了流s的failbit值,则该函数返回true

s.bad() 如果设置了流s的badbit值,则该函数返回true

s.good() 如果流s处于有效状态,则该函数返回true

s.clear() 将流s中的所有状态值都重设为有效状态

s.clear(flag) 将流s中的某个指定条件状态设置为有效。flag的类型是strm::iostate

s.setstate(flag) 给流s添加指定条件。flag的类型是strm::iostate

s.rdstate() 返回流s的当前条件,返回值类型为strm::iostate

badbit标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了。如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置failbit标志,这种导致设置failbit的问题通常是可以修正的。eofbit是在遇到文件结束符时设置的,此时同时还设置了failbit。

3、下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:

(1)程序正常结束。作为main返回工作的一部分,将清空所有输出缓冲区。

(2)在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。

(3)用操纵符显示地刷新缓冲区,例如行结束符endl。

(4)在每次输出操作执行完后,用unitbuf操纵符设置流的内部状态,从而清空缓冲区。

(5)可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。

4、除了endl操纵符,C++语言还提供了另外两个类似的操纵符。第一个是经常使用的flush,用于刷新流,但不在输出中添加任何字符。第二个则是比较少用的ends,这个操纵符在缓冲区中插入空字符null,然后刷新它:

cout << “hi!” << flush;

cout << “hi!” << ends;

cout << “hi!” << endl;

如果需要刷新所有输出,最好使用unitbuf操纵符。这个操纵符在每次执行完写操作后都刷新流:

cout << unitbuf << “first” << “second” << nounitbuf;

等价于:

cout << “first” << “second” << flush;

nounitbuf操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式。

5、tie函数可用istream或ostream对象调用,使用一个指向ostream对象的指针形参。调用tie函数时,将实参流绑在调用该函数的对象上。如果一个流调用tie函数将其本身绑在传递给tie的ostream实参对象上,则该流上的任何IO操作都会刷新实参所关联的缓冲区。一个ostream对象每次只能与一个istream对象绑在一起。如果在调用tie函数时传递实参0,则打破该流上已存在的捆绑。

6、由于历史原因,IO标准库使用C风格字符串而不是C++ string类型的字符串作为文件名。在创建fstream对象时,如果调用open或使用文件名作初始化式,需要传递的实参应为C风格字符串,而不是标准库string对象。程序常常从标准输入获得文件名。通常,比较好的方法是将文件名读入string对象,而不是C风格字符数组。假设要使用的文件名保存在string对象中,则可调用c_str成员获取C风格字符串。

7、如果程序员需要重用文件流读写多个文件,必须在读另一个文件之前调用close关闭前一个文件,并调用clear清除该流的状态。

8、文件模式

in 打开文件做读操作

out 打开文件做写操作

app 在每次写之前找到文件尾

ate 打开文件后立即将文件定位在文件尾

trunc 打开文件时清空已存在的文件流

binary 以二进制模式进行IO操作

9、stringsteam提供转换和/或格式化

C++ Primer Chapter7

星期五, 23 4 月, 2010

1、函数由函数名以及一组操作数类型唯一地表示。C++使用调用操作符(即一对圆括号)实现函数的调用。正如其他操作符一样,调用操作符需要操作数并产生一个结果。调用操作符的操作数是函数名和一组(有可能是空的)由逗号分隔的实参。

2、形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值,如果形参为引用类型,则它只是实参的别名。

函数的形参可以是指针,此时将复制实参指针。与其他非引用类型的形参一样,该类形参的任何改变也仅作用于局部副本(形参复制实参的值)。如果函数将新指针赋值给形参,主调函数使用的实参指针的值没有改变。事实上被复制的指针只影响对指针所指对象的赋值,即如果函数形参是非const类型的指针,则函数可通过指针实现赋值,修改指针所指向对象的值。

可以将指向const对象的指针初始化为指向非const对象,但不可以让指向非const对象的指针指向const对象。

在调用函数时,如果该函数使用非引用的非const形参,则既可给该函数传递const实参也可传递非const的实参。因为初始化复制了初始化式的值,所以可以用const对象初始化非const对象,反之亦然。

3、从C语言背景转到C++的程序员习惯通过传递指针来实现对实参的访问。在C++中,使用引用形参则更安全和自然。

如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为const引用。

非const引用形参只能与完全同类型的非const对象关联。应该将不修改相应实参的形参定义为const引用。如果将这样的形参定义为非const引用,则毫无必要的限制了该函数的使用。如:

int incr(int &val);

short v1 = 0;

int v2 = incr(v1);    // int &只能绑定int对象

应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活。这样的形参既不能用const对象初始化,也不能用字面值(常量)或产生右值的表达式实参(临时变量)初始化。

4、使用数组形参或指针形参传递数组,编译器只会检查实参是不是指针、指针的类型和数组元素的类型是否匹配,而不会检查数组的长度。如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型的一部分。编译器检查数组实参的大小与形参的大小是否匹配。

&arr两边的圆括号是必需的,因为下标操作符具有更高的优先级:

f(int &arr[10])    // error: arr is an array of references

f(int (&arr)[10])    // ok: arr is a reference to an array of 10 ints

5、C++中的省略符形参是为了编译使用了varargs的C语言程序。关于如何使用varargs,请查阅所用C语言编译器的文档。对于C++程序,只能将简单数据类型传递给含有省略符形参的函数。实际上,当需要传递给省略符形参时,大多数类类型对象都不能正确地复制。

6、为了主函数main的返回值独立于机器,cstdlib头文件定义了两个预处理变量,分别表示程序运行成功和失败:

#include <cstdlib>

int main()

{

    if(some_failure)

        return EXIT_FAILURE;

    else

        return EXIT_SUCCESS;

}

7、当函数返回引用类型时,没有复制返回值。相反,返回的是对象本身。理解返回引用至关重要的是:千万不能返回局部变量的引用。

返回引用的函数返回一个左值(变量的别名,可以赋值)。

8、默认实参是通过给形参表中的形参提供明确的初始值来指定的。程序员可为一个或多个形参定义默认值。但是,如果有一个形参具有默认实参,那么,它后面所有的形参都必须有默认实参。

9、只有当定义它的函数被调用时才存在的对象称为自动对象。static局部对象一旦被创建,在程序结束前都不会被撤销。

10、内联函数应该在头文件中定义,这一点不同于其他函数。

编译器隐式地将在类内定义的成员函数当作内联函数。

内联说明对于编译器来说只是一个建议,编译器可以选择忽略这个建议。

11、每个成员函数都有一个额外的、隐含的形参this。

const改变了隐含的this形参的类型(Object *const this变成了const Object *const this)。用这种方式使用const的函数称为常量成员函数。由于this是指向const对象的指针,const成员函数不能修改调用该函数的对象。

const对象、指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用它们来调用非const成员函数,则是错误的。

12、在冒号和花括号之间的代码成为构造函数的初始化列表。除非在初始化列表中有其他表述,否则具有类类型的成员皆被其默认构造函数自动初始化。

Object: iMin(0), iMax(100) {}    // Object构造函数

13、由编译器创建的默认构造函数通常成为合成的默认构造函数,它将依据如同变量初始化的规则初始化类中所有成员。对于具有类类型的成员,则会调用该成员所属类自身的默认构造函数实现初始化。内置类型成员的初值依赖于对象如何定义。如果对象在全局作用域中定义(即不在任何函数中)或定义为静态局部对象,则这些成员将被初始化为0。如果对象在局部作用域中定义,则这些成员没有初始化。除了给它们赋值之外,处于其他任何目的对未初始化成员的使用都没有定义。

14、允许将形参定义为函数类型,但函数的返回类型则必须是指向函数的指针,而不能是函数。具有函数类型的形参所对应的实参将被自动转换为指向相应函数类型的指针。