9.7 改进的错误检查
到目前为止,没有定义require.h中的函数却使用了它们(尽管assert()也被用在适当的地方来检查程序错误),现在该定义这个头文件了。在这里使用内联函数是便利的,因为它们允许放在头文件中,这样简化了包的使用过程。只要包含头文件,就不必担心连接一个实现文件。
应该注意异常处理机制(在本书的第2卷有详细的描述)为处理各种错误提供了一种更加有效的方法(特别是对于那些想恢复的错误),而不只是中止程序的运行。异常出现在诸如用户没有为一个文件提供足够的命令行参数,或者文件不能打开时。这时,程序不会继续运行。因此,可以调用标准的C库函数exit()。
下面的头文件将放在本书的根目录中,所以它可以从所有的章节里访问。
默认值提供合理信息,必要时可以改变。
从上面可以看到,没有使用char类型的参数,而是使用了const string&参数。这允许把char和string作为这些函数的参数,一般说来,这样做更有用(在我们自己编码时也可能想这样)。
在requireArgs()和requireMinArgs()的定义中,增加了一个表示命令行中参数数目的参数,因为argc包括了总是作为第一个参数的程序名,所以argc比实际的命令行参数数目多一。
请注意在每一个函数中局部声明“using namespace std”的使用。这是因为声明不对时,编译器不会包含namespace std中标准的C库函数。这样将不能使用namespace std中的函数而导致编译错误。局部声明允许require.h同正确的和不正确的库一起工作,它不会为包含了这个头文件的任何人打开namespace std。
下面是一个测试require.h的简单程序。
为了打开文件也许想进一步地在require.h中加一个宏。
可以像如下使用:
刚开始,这种做法看起来是吸引人的,因为只要敲很少的代码。它虽然有一定的安全性,但最好还是避免这样做。应该注意:宏看起来像函数,但其行为方式不一样。它实际上创建一个对象(in),该对象的作用范围不仅仅在宏内。我们现在可以理解这一点,但是对于程序设计的新手和代码维护人员来说,令他们感到迷惑的就不止这一点。所以,只要有可能就尽量不去使用预编译宏。