语句
|
在上面例子,要特别注意while循环中定义的变量和for循环中定义的变量的生存期的区别。
另外,在switch语句中,case标号必须是整型常量表达式。若要switch语句内定义变量,只能在最后一个case标号或者default标号后面定义变量。这个规则主要是为了避免出现代码跳过变量的定义和初始化的情况。当需要在某个caes语句中定义变量时,可以使用块语句,然后在这块语句中定义变量。
当抛出一个异常时,首先要搜索的是抛出异常的函数,如果没有找到匹配的catch子句,则终止这个函数的执行。然后在调用这个函数的函数中继续寻找相匹配的catch。如果仍然没有找到,该函数终止,继续向上,直到找到相匹配的catch。如果不存在处理该异常的catch,程序的运行就要跳转到名为 terminate的标准库函数(头文件<exception>)。该函数的行为依赖于系统,通常它的行为将导致程序非正常退出。
C++标准库异常类定义在四个头文件中:
1) <exception>头文件中定义了异常类exception;
2) <stdexcept>头文件中定义了几种常见的异常类。
3) <new>头文件中定义了bad-alloc异常类。当new无法分配内存时将抛出该异常类对象。
4) <type_info>头文件中定义了bad_cast异常类。当dynamic_cast失败时将抛出该异常类对象。
标准异常类之间的关系:exception派生出runtime_error类和logic_error类。由runtime_error派生出range_error、overflow_error、underflow_error;由logic_error派生出domain_error、invalid_argument、length_error、out_of_range。
exception | 最常见的问题 |
runtime_error | 运行时错误:仅在运行时才能检测到的问题 |
range_error | 运行时错误:生成的结果超出了有意义的值域范围 |
overflow_error | 运行时错误:计算上溢 |
underflow_error | 运行时错误:计算下溢 |
logic_error | 逻辑错误:可在运行前检测到的问题 |
domain_error | 逻辑错误:域错误 |
invalid_argument | 逻辑错误:无效参数 |
length_error | 逻辑错误:试图生成一个超出该类型最大长度的对象 |
out_of_range | 逻辑错误:使用一个超出有效范围的值 |
注:运行时错误是指在某语句计算过程中产生的错误,逻辑错误是指在某语句执行前检查到的错误。
几个预处理常量
1) __FILE__ 文件名
2) __LINE__ 当前行号
3) __TIME__ 文件被编译的时间
3) __DATE__ 文件被编译的日期
assert宏定义在头文件<cassert>中,其使用语法形如:assert(expr);
其中,当expr结果为0时,assert输出信息并且终止程序的执行;否则,assert不做任何操作。
函数
如果main函数最后一个语句不是返回语句,则编译器会隐式地插入返回0的语句。<cstdlib>定义了两个预处理变量:EXIT_FAILURE和EXIT_SUCCESS,分别代表程序运行失败和成功。
int fun(int (&arr)[10]);
注意:(& ref)两边的圆括号不能少。否则,int &arr[10]表示有10个引用元素的数组(注意:C++中不能定义元素类型为引用的数组)。
注:数组元素类型不能为引用、void、函数类型或者抽象类类型。 |
在无法列举出传递给函数的所有实参的类型的数目时,可以作用省略符形参。省略符形参暂停了类型检查机制。当调用函数时,可以有0或者多个实参,而实参的类型未知。有两种形式:
void foo(parM_list, ...);
void foo(...);
第一种形式为特定数目的形参提供了声明。在这种情况下,当函数被调用时,对于与显示声明的形参相对应的实参进行类型检查,而对于与省略号对应的实参则暂停类型检查。在第一种形式中,形参后面的逗号是可选的。
|
内联指示符(inline specification)对于编译器来说只是一个建议,编译器可以选择展开或者忽略它。大多数编译器不支持递归函数的内联。
内联函数应该在头文件中定义,因为内联函数的定义对编译器必须是可见的,以便编译器能够在调用点内联展开该函数的代码。
每个非静态成员函数都有一个额外的、隐含的形参 this。
在定义和声明类成员函数时,可以在形参表后面用const修饰函数,表明这是一个const成员函数。const成员函数相当于把this指针指向的对象修饰成了const对象,所以不能在const成员函数中对this指向的对象进行修改。
注:const对象只能调用const成员函数,这也是const成员函数存在的理由。 |
|
实参类型转换
为了确定最佳匹配,编译器将实参类型到相应形参类型的转换划分为四个等级,优先顺序如下:
1) 精确匹配:实参与形参类型相同;
2) 通过类型提升实现的匹配;
3) 通过标准转换实现的匹配;
4) 通过类类型转换实现的匹配。
仅当形参是引用或指针时,形参有const和无const的才是重载的。例如:
void foo(const string);
void foo(string);
这两个函数不是重载函数,是重复声明。因为不论哪一个函数中形参都不会影响实参。
在引用函数名但又没有调用该函数时,函数名将被自动解释为指向函数的指针。此时,直接使用函数名和在函数名前加上取地址符(&)是等效的。
函数指针只能通过同类型的函数、函数指针或者0值常量表达式来初始化或赋值。
使用函数指针调用它所指向的函数时,可以把指针当作函数名那样调用pf(...),也可以用指针的解引用形式调用(* pf)(...),效果一样。
函数指针形参有两种形式:一是声明为函数类型,此时将自动转换为函数指针;二是显示声明为函数指针。例如:
// two equivalent declarations
void foo(void (int)); // foo has a parameter of function type
void foo(void (*)(int)); // foo has a parameter of a pointer to function
函数可以返回函数指针。
void (*foo(int))(int);
foo是一个参数为int类型并且返回值为void (*)(int)类型的函数指针的函数。如果用typedef要清晰很多,如前面的声明等价于下面的声明:
typedef void (* PF)(int);
PF foo(int);
允许将函数形参定义为函数类型,但不允许函数的返回类型为函数类型,此时只能返回函数指针。例如:
typedef void func(int);
void f1(func); // ok: f1 has a parameter of function type
func* f3(int); // ok: f3 has returns a pointer to function type
func f2(int); // error: f2 has a return type of function type
对于指向重载函数的指针,指针的类型必须与重载函数的一个版本精确匹配。
[2] Thinking in C++(Volume Two, Edition 2)
[3] International Standard:ISO/IEC 14882:1998