1、编译器能以任意可行的顺序对实参求值。(https://www.cnblogs.com/easonliu/p/4224120.html)
2、局部变量:形参和函数体内部定义的变量。
3、如果局部静态变量没有显式的初始值,它将执行值初始化。内置类型的局部静态变量初始化为0。
4、如果一个函数永远也不会被我们用到,那么它可以只有声明没有定义。函数声明也称作函数原型。
5、函数参数传递:传引用调用、传值调用。
6、当形参为const,且为顶层const时:
- 和其他初始化过程一样,当用实参初始化形参时会忽略掉顶层const。当形参由顶层const时,传给它常量or非常量对象都是可以的。
- 以下重载不可行:
void fcn(const int i) {..} void fcn(int i) {..}
由于顶层的const被忽略,所以传入两个fcn函数的参数可以完全一样。
7、数组形参:
-
void print(const int*); void print(const int[]); void print(const int[10]);//实际上不一定由10个元素
以上三个函数等价,每一个函数的唯一形参都是const int*类型。
int i = 0, j[2] = {0, 1}; print(&i);//正确, &i类型为int* print(j);//正确, j转换成int*且指向j[0]
- C++允许将变量定义为数组的引用,形参也可以是数组的引用。
void print(int (&arr) [10]) { ... }
这样子的写法固定了数组的维度。
int i = 0, j[2] = {0, 1}; int k[10]; print(&i);//错误,不是10个元素的数组 print(j);//同上 print(k);//正确
8、argv的第一个元素指向程序的名字或一个空字符串。
9、含有可变形参的函数:使用initializer_list<T>
- C++11新特性,如果函数的实参数量未知但全部实参类型都相同,则可以使用initializer_list。定义在同名的头文件中。
- initializer_list的对象永远都是常量值。赋值或拷贝一个initializer_list对象不会拷贝列表中的元素;拷贝后原始列表和副本共享元素。
- 使用迭代器访问。
- 想向initializer_list形参传递一个值的序列,则必须把序列放在一对花括号内。
if(expected != actual) error_msg({"xxx", "xxx"});
10、C的省略符形参。
11、不要返回局部对象的引用或指针。
const string& manip() { string ret; if(!ret.empty()) return ret; else return "Empty"; }
上述两条return语句都是错误的。第二个中,字符串字面值转换为了一个局部临时string对象。
new的空间在堆区。
12、列表初始化返回值。C++11。
13、引用返回左值,其他返回类型得到右值。可以像使用其他左值那样来使用返回引用的函数调用。可以为返回类型是非常量引用的函数结果赋值。
14、返回数组指针
- 返回数组指针的函数:int (*func(int i))[10];
- 尾置返回类型:
auto func(int i) -> int(*)[10];
- 使用decltype
int odd[] = {1,3,5,7,9}; int even[] = {0,2,4,6,8}; decltype(odd) *arrPtr(int i) { return (i % 2)? &odd: &even; }
注意decltype的结果是一个数组。
15、函数重载
- 顶层const不影响传入函数的对象。一个拥有顶层const的形参无法与另一个没有顶层const的形参区分开来:
Record lookup(Phone); Record lookup(const Phone);//error Record lookup(Phone*); Record lookup(Phone* const);//error
- 如果形参是某种类型的指针或引用,那么可以通过区分其指向的是常量对象或非常量对象实现重载。
Record lookup(Account&); Record lookup(const Account&); Record lookup(Account*); Record lookup(const Account*);
const对象只能传递给const形参。因为非常量可以转换成const,上面4个都可以。但编译器优先选择非常量版本的函数。
-
class A{ public: A(A a){}//error };