自动对象:存在于块执行期间的对象,在块的执行结束后,其值变成未定义的
参数传递
with const
实参传形参的时候,忽略掉实参的顶层const
形参用const修饰后,在方法体内该形参变成顶层const
const+引用/指针的初始化规则可以应用于函数,形参看作声明的变量,实参看作初始值
Best Practice:对于不希望产生副作用的引用参数,用const修饰
数组传参
数组类型与指针类型在传参时等价,编译器会把数组转换成指向第一个元素的指针
对于数组类型,传递beg和end指针(迭代器)是比较符合stl设计规范的
多维数组参数的第二维以后的大小都不能省略
可变形参
initializer_list<T> 
void error_msg_handler(const int error_no, const std::initializer_list<std::string> il) { std::cout << error_no << std::endl; for (auto& msg : il) { std::cout << msg << std::endl; } } // ... if (expected != actual) { error_msg_handler(1, {"functionX", expected, actual}); } else { error_msg_handler(0, {"functionX", "okay"}); }
省略符形参:…
出现在形参列表最后一个位置,不会对形参做类型检查
返回
返回引用
若返回类型非引用,则会进行值拷贝,参见↓
不允许返回局部对象的指针或者引用
函数调用运算符的优先级与点和箭头运算符相同,且都满足左结合律
返回引用则会返回左值,可以对其进行其他操作
可以返回const引用
返回数组指针
数组无法被拷贝,所以不能返回一个数组,但是可以返回数组的指针或者引用
利用别名来规定返回的数组维度
typedef int arrT[10]; // arrT是一个int[10] using arrT = int[10]; // 等价 arrT* func(int i); // 返回一个指向int[10]的指针
不使用别名?得用这种复杂的形式:
Type (*funcName(para_list) [dimension]); // e.g. // 逐层理解其含义: // *func(int i) 表示可以对函数返回值进行解引用 // *func(int i) [10] 表示解引用的结果会是一个大小为10的数组 // int ...表示数组类型为int int (*func(int i) [10]);
C++11还提供了一种新的形式:尾置返回类型
auto放在前面,后面用箭头加返回类型
auto func() -> int (*)[10] { // ... }
decltype(xxx) * 也可以,但是注意xxx的维度要和返回值一致
int odd[] = {1, 3, 5, 7, 9}; int even[] = {2, 4, 6, 8, 0}; decltype(odd) * arrPtr(int i) { return (i % 2) ? &odd : &even; } // another file int odd[] = {1, 3, 5, 7, 9}; int even[] = {1, 3, 5, 7, 9, 11}; // fault: 维度不同 decltype(odd)* func() { return &even; }
重载
参数类型或数量不同即可
注意顶层const无法区别参数类型,底层可以
Record lookup (Account&); // 函数作用于Account 的引用 Record lookup(const Account&); // 新函数,作用于常量引用 Record lookup (Account*); // 新函数,作用于指向 Account 的指针 Record lookup(const Account*); // 新函数,作用于指向常量的指针
const_cast在此时有一个作用:把不得不返回const引用的函数重载成非const的版本
// 这个函数不能返回string&,因为s1和s2都是const string& const string& shorterString(const string& s1, const string& s2) { return s1.size() <= s2.size() ? s1 : s2; } string& shorterString(string& s1, string& s2) { auto& s = shorterString(const_cast<const string&>(s1), const_cast<const string&>(s2)); return const_cast<string&>(s); }
参数默认值
基本和其他语言差不多
注意不能用局部变量当参数默认值
用作默认实参的名字在函数声明所在的scope里解析,而这些名字的求值发生于函数调用时
using sz = string::size_type; sz wd = 80; char def = ''; sz ht(); string screen(sz = ht(), sz = wd, char = def) void f2() { def = '*'; // 改变了默认参数绑定的变量 sz wd = 100; // 隐藏全局变量,但是不影响默认参数绑定的变量 window = screen(); // screen(ht(), 80, '*') }
constexpr函数↓
函数指针
把函数名当值使用的时候,函数自动转换为指针,加了取地址符也是一样的
使用的时候也是没啥区别
bool lengthCompare(const string& s1, const string& s2) { // ... } bool (*pf) (const string&, const string&); // pf是一个指针,指向一个返回bool的,参数如右的函数 pf = lengthCompare; // pf 指向名为lengthCompare 的函数 pf = &lengthCompare; // 等价的赋值语句:取地址符是可选的 bool bl = pf("hello", "goodbye"); // 调用 lengthCompare 函数 bool b2 = (*pf) ("hello", "goodbye"); // 一个等价的调用
获取重载函数的指针时,函数指针变量的上下文会用于区分不同的重载版本
函数指针作为形参时,可以不加*
void foo(bool pf(const string&, const string&));
typedef
// Func 和 Func2 是函数类型 typedef bool Func (const string&, const string&); typedef decltype (lengthCompare) Func2; // 等价的类型,但是注意decltype不会自动转换成指针 using F = bool (const string&, const string&); // FuncP 和 FuncP2 是指向函数的指针 typedef bool(*FuncP) (const string&, const string&); typedef decltype (lengthCompare) *FuncP2; // 等价的类型 using PF = int (*) (const string&, const string&); // 重新声明foo: void foo(Func); void foo(FuncP2);