int count_calls()
{
static size_t ctr = 0; //调用结束后,这个值依然有效
}
int main(){
for(size_t i = 0 ; i < 10 ; i++ ){
cout << count_calls << endl;
}
return 0 ;
}
void fcn(const int i){ /* fcn能够读取i,但不能向i写值*/}
例如:
string::size_type find_char(string &s ,char c,string::size_type &occurs);
find_char("Hello World",'o',ctr); //错误,普通引用的形参不能传入字面值,应使用const string &s
数组的两个特殊性质:不允许拷贝;在使用时将转化为指针。
例如: 下面三个 print 函数的声明是等价的,形参均为 const int*类型。
void print(const int[]);
void print(const int*);
void print(const int[10]); //这里的维度可以表示我们期望数组有多少个元素,实际不一定。
void print(int (&arr)[10]){ //括号不可省略,否则是一个引用的数组。
for(auto elem : arr){
cout << elem << endl;
}
}
void print(int (*matrix)[10] , int rowSize){ /* 传入的是一个指向大小为10的int型数组的指针 */}
void print(int *matrix[10]); //传入的是一个10个指针构成的数组
上述声明等价于:
void print(int matrix[][10] , int rowSize){/* 实际形参是一个指向10个整数数组的指针 */}
假定 main 函数位于可执行文件 prog 之内,可以向程序传递下面的选项。
prog -d -o ofile data0
这些命令行选项通过两个(可选的)形参传递给 main 函数。
int main(int argc, char *argv[]){ }
注: argv 第一个元素指向程序的名字或一个空字符串。最后一个指针之后的位置保证 0。
在上面的例子中:
argv[0] = "prog";
argv[1] = "-d";
argv[2] = "-o";
argv[3] = "ofile";
argv[4] = "data0";
argv[5] = "0";
argc = 5;
为了编写能处理不同数量实参的函数,C++11 新标准提供了两种主要的方法:
如果实参数量未知但实参的类型均相同,可以使用 initializer_list 类型的形参。
initializer_list 提供的操作:
指同一作用域内函数名相同而形参列表不同。
例如:
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 Accout*); //新函数,作用于常量指针
不同作用域中无法重载函数名,内层作用域中的名字将隐藏外层作用域中的命名实体。
例如:
void print(const string &);
void test(){
void print(int);
print("Hello\n"); //错误,外层的print被隐藏掉了。
}
调用含有默认实参的函数时,可以包含该实参,也可以省略该实参。
typedef string::size_type sz;
string screen(sz ht = 24 ; sz wid = 80; char bg = ' ');
screen(); //相当于screen(24,80,' ');
screen(66); //相当于screen(66,80,' ');
screen(68,90); //相当于screen(66,90,' ');
screen(68,90,'#');
screen(,,'#'); //错误,只能忽略尾部实参。
内联函数可以避免函数调用的开销。可以让程序在编译的时候内联的展开。
inline const string & shorterString(const string &s1,const string &s2){
return s1.size() < s2.size() ? s1 : s2;
}
内联只是向编译器发出一个请求,编译器可以忽略。
constexpr 函数的参数和返回值必须是字面值类型。且函数体只能有一条 return 语句。
constexpr int new_sz(){return 42};
允许 constexpr 函数值并非一个常量。如下例中,若实参为常量表达式,返回值也为常量表达式。
constexpr size_t scale(size_t cnt){ return new_sz() * cnt}
int arr[scale[2]]; //正确
int i = 10;
int arr2[scale[i]]; //错误
函数指针指向的是函数而非对象。函数指针的类型由它的返回类型和形参类型共同决定。
例如:
bool lengthCompare(const string &,const string &) //类型为bool(const string &,const string &)
bool (*pf)(const string &,const string &);
声明函数指针时只要把函数名换成指针。括号必不可少,否则返回值为 bool*。
当我们把函数名作为一个值来使用时,该函数自动转化为指针。
pf = lengthCompare;
pf = &lengthCompare; //取地址符为可选项
我们还可以直接使用指向函数的指针来调用该函数,无需进行解引用操作。
bool b1 = pf("hello","goodbye");
bool b2 = *pf("hello","goodbye"); //等价
不同函数类型的函数指针之间不存在相互转化,但可以赋值为空指针。
函数指针可以作为函数形参,当使用时,直接使用函数名即可。
函数类型与函数指针略有不同,但作为形参时,编译器会将函数类型转化为指针。
函数指针作为返回值:
和形参不同,返回类型不会自动由函数类型转化为指针。且函数类型不可作为返回值。
using F = int(int*,int); //F是函数类型
using PF = int (*) (int *,int); //PF是函数指针类型
PF f1(int); //正确,返回的是函数指针
F f2(int); //错误,不可返回函数类型
F* f3(int); //正确,返回的是函数指针
上述语句可以等价于:
int (*f1(int))(int* ,int);
若 f1 后没有(int) ,f1 是一个函数指针,因为有,所以 f1 是一个函数,参数为 int,返回值为一个函数指针。