参数传递问题
- 形参初始化的机理和变量初始化一样。
- 引用传递(passed by reference):又称传引用调用(called by reference),指形参是引用类型,引用形参是它对应的实参的别名。
- 值传递(passed by value):又称传值调用(called by value),指实参的值是通过拷贝传递给形参。
- 当初始化一个非引用类型的变量时,初始值被拷贝给变量。
- 函数对形参做的所有操作都不会影响实参。
- 指针形参:传入的也是指针值的拷贝,函数内部改变其值不影响实参的值。常用在C中,C++建议使用引用类型的形参代替指针。
传引用参数
- 通过使用引用形参,允许函数改变一个或多个实参的值。引用形参绑定初始化它的对象,而非对象的副本。
- 经常用引用形参来避免不必要的复制。
- 如果无需改变引用形参的值,最好将其声明为常量引用。
const形参和实参
void fcn(const int i){}
void fcn(int i){}
- 当形参有顶层const时,传给它常量对象或者非常量对象都是可以的。
- string& s 形参无法接收如"hello world"的实参,需要定义形参为const string& s
数组形参
void print(const int*);
void print(const int[]);
void print(const int[10]);
void print(const char* cp){
if(cp)
while(*cp)
cout<<*cp++;
}
void print(const int *beg,const int *end){
while(beg!=end)
cout<<*beg++<<endl;
}
int j[2] = {0,1};
print(begin(j),end(j));
void print(const int ia[],size_t size){
for(size_t i = 0;i != size;++i){
cout<<ia[i]<<endl;
}
}
int j[] = {0,1};
print(j,end(j)-begin(j));
数组引用形参
void print(int (&arr)[10]){ //arr是具有10个整数的整型数组的引用
for(auto elem : arr)
cout<<elem<<endl;
}
传递多维数组
void print(int (*matrix)[10],int rowSize){}
void print(int matrix[][10],int rowSize){} //等价定义
可变形参 initializer_list
initializer_list<T> lst;
initializer_list<T> lst{a,b,c...};
lst2(lst)
lst2 = lst
lst.size()
lst.begin()
lst.end()
- 是一种模板类型,对象中的元素永远是常量值,类型相同
- 类型不同时,可用可变参数模板
void error_msg(initializer_list<string> il){
for(auto beg = il.begin();beg!=il.end();++beg)
cout<<*beg<<" ";
cout<<endl;
}
error_msg({"functialX",expected,actual})
省略符形参
void foo(parm_list,...);
void foo(...);
函数返回值
- 值的返回:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。非引用类型也存在拷贝。
- 不要返回局部对象的引用或指针。
- 引用返回左值:函数的返回类型决定函数调用是否是左值。调用一个返回引用的函数得到左值;其他返回类型得到右值。
- 列表初始化返回值:函数可以返回花括号包围的值的列表。
vector<string> process(){
...
return {};
}
返回数组指针或引用
typedef int arrT[10];
using int = arrT[10];
arrT* func(int i);
int (*func(int i))[10];
auto func(int i) -> int(*)[10];
int odd[] = {};
int even[] = {};
decltype(odd) *arrPtr(int i){
return (i%2) ? &odd : &even;
}
函数重载
- 一个有顶层const的形参和没有它的函数无法区分。
Record lookup(Phone);
Record lookup(const Phone);
Record lookup(Phone*);
Record lookup(Phone* const);
Record lookup(Account&);
Record lookup(const Account&);
Record lookup(Account*);
Record lookup(const Account*);
const_cast和重载
const string& shorterString(const string& s1,const string& s2){
return s1.size() <= s2.size() ? s1 : s2;
}
string& shorterString(string& s1,string& s2){
auto &r = shorterString(const_cast<const string&>(s1),const_cast<const string&>(s2));
return const_cast<string&>(r);
}
内联函数
- 普通函数的缺点:调用函数比求解等价表达式要慢得多。
- inline函数可以避免函数调用的开销,可以让编译器在编译时内联地展开该函数。
constexpr函数
- 指能用于常量表达式的函数。
- constexpr int new_sz() {return 42;}
- 函数的返回类型及所有形参类型都要是字面值类型。
函数指针
bool lengthCompare(const string&,const string&);
bool (*pf)(const string&,const string&);
- 当我们把函数名作为一个值使用时,该函数自动地转换成指针。
pf = lengthCompare;
pf = &lengthCompare;
bool b1 = pf("hello","goodbye");
bool b2 = (*pf)("hello","goodbye");
bool b3 = lengthCompare("hello","goodbye");
重载函数的指针
void ff(int*);
void ff(usigned int);
void (*pf1)(unsigned int) = ff;
函数指针形参
void useBigger(const string& s1,const string& s2,bool pf(const string&,const string&));
void useBigger(const string& s1,const string& s2,bool (*pf)(const string&,const string&));
useBigger(s1,s2,lengthCompare);
//简化
typedef bool Func(const string&,const string&);
typedef decltype(lengthCompare) Func2;
typedef bool(*FuncP)(const string&,const string&);
typedef decltype(lengthCompare) *FuncP2;
void useBigger(const string&,const string&,Func); //Func自动转为指针
void useBigger(const string&,const string&,FuncP2);
返回指向函数的指针
using F = int(int*,int);
using PF = int(*)(int*,int);
PF f1(int);
F *f1(int);
//直接声明
int (*f1(int))(int*,int);
//尾置返回类型
auto f1(int) -> int(*)(int*,int);
//将auto和decltype用于函数指针类型
string::size_type sumLength(const string&,const string&);
string::size_type largerLength(const string&,const string&);
decltype(sumLength) *getFcn(const string&);