c++从入门到放弃(五)函数基础

​ 坑!c++

5.1 参数

int f(i++,i) //默认是不清楚先计算i仍是i++的,没有规定实参的求值顺序,可是,能够假设从后往前计算,c语言中是这个过程 int f(int a,int) //形参名是可选的,通常状况下须要一个名字,不提供也行,就是找不到这个形参 int f() {
    static int a=0;
    //这个局部静态对象的生命周期是一直到整个进程结束!进程!
    //未显式初始化则默认初始化为0(内置类型)
}
int f(int ,int);
	//声明里面不必定须要形参名,注意是声明!
	//函数三要素:返回类型(不写其实默认为int),函数名,形参类型
int f(int &a,int &b) //传引用,可修改 //可是不能够传一个字面值,好比f(1,2),引用类型不能够初始化为字面值 int f(const int &a,const int &b) //这就能够了。。。。f(1,2)没有问题 //使用引用能够避免拷贝,特别大的字符串的时候! //传递数组的时候,实际上传递的是数组的指针 //多维数组就不说了 //若是有问题,想一想这样初始化这个形参是否会出现问题 复制代码

若是不清楚形参的数量,可使用省略符形参数组

void foo(int a,...) void foo(...) 复制代码

5.2 返回值

在含有return语句的循环后面应该也有一条return语句,若是没有的话就是错误的,若是编译器没有发现这个错误,则运行时的行为就是未定义的。函数

for(int i=0;i<n;i++)
    if(i>8)
        return;
return;		//必须写以防止最后不返回
复制代码

不要返回局部对象的引用或者指针,局部变量使用的空间在函数结束后是会被释放的,因此不能够返回局部变量的指针或者引用。可是返回局部变量的值是能够的,由于使用的是拷贝的数据。ui

const string &manip() {
    string ret;
    if(!ret.empty())
        return ret;	//错误,返回局部变量的引用
    else
        return "abv";	//错误,这是一个局部临时量,在函数结束的时候同样会被清空空间
}
复制代码

返回类类型或者引用,指针之类的函数,可使用函数调用的结果访问其成员spa

auto z=shorterString(s1,s2).size();
//返回一个引用类型的函数能够当作左值
char &get_val(string &s,int x) {return s[x];}
int main() {
    get_val(s,x)=1;	//直接当作左值修改
}
复制代码

也可使用列表初始化返回指针

return {1,2,3}	//通常用来返回容器类型
复制代码

5.3 重载

​ 若是同一做用域内的几个函数名字相同可是形参列表不一样(形参数量形参类型),则称之为重载函数。code

注意:main函数是不能重载的对象

int fun(int a,int b);
int fun(int a) int fun(char c) int fun(int c) //这就不是重载 int fun(int) //这也不是重载 复制代码

​ 注意,函数参数是不承认顶层const的,因此默认顶层const加不加都同样。生命周期

int fun(int a);
int fun(const int a);		//不能够,顶层const

int fun(int *a);
int fun(int * const a);		//不能够,顶层const

//若是形参是某种类型的指针或者引用,则经过区分其指向的是常量对象仍是很是量对象能够实现函数重载,此时const是底层的
int fun(int &);
int fun(const int &);		//能够重载,底层const
int fun(int *);
int fun(const int *);		//能够重载,底层const
复制代码

​ 注意须要避免函数重载的二义性!进程

​ 在不一样的做用域中没法重载函数!

5.4 特殊特性

​ 能够为函数形参赋值默认实参(在声明中赋值)

int fun(int a,int b,int c=1);
//能够为一个或者多个形参赋值默认值,可是,一旦一个形参赋值了,则后面的形参都必须有默认实参
int fun(int a,int b=1,int c);		//没法分辨fun(1,2)的二义性
//注意没法修改一个已经存在的默认值
int fun(int ,int ,int c=2);			//错误
//可是能够添加默认实参
int fun(int a,int b=2,int c=1);		//正确

##函数调用时实参按其位置解析,默认实参负责填补函数调用缺乏的尾部实参
int fun(string a="123",int a=1,int b=2);
fun(,2,3);		//错误,默认补充尾部默认参数,想修改哪一个那前面的都不能跳过!
    			//只能忽略尾部的实参
fun("1",2+1);	//假如想修改b这个程序会和预期不符,因此要消除二义性
复制代码

​ 内联函数,能够避免函数调用的开销,不会进入到函数的地址区,而是经过编译器直接将函数代码"粘贴"到对应位置,因此不适用于大型的函数,只适用于小型的,频繁调用的函数。

inline int f(int a,int b) {return a>b?a:b;}
cout<<f(1,2)<<endl;
//等价于
cout<<1>2?1:2<<endl;
复制代码

​ assert预处理宏

assert(expr)
    //表达式为假则输出信息并终止程序的运行
    //为真则什么也不作
复制代码

5.5 函数匹配

具体操做以下

void f();
void f(int);
void f(int,int);
void f(double,double=3.14);

f(5.6);

(1)肯定候选函数
		1.与被调用的函数重名
		2.其声明在调用点可见
//无淘汰
(2)肯定可行函数
		1.形参数量与本次调用提供的实参数量相等(考虑默认参数但是可行的)
		2.每一个参数的类型与对应的形参类型相同,或者能转换成形参类型
//淘汰第1,3
//若是这步未找到可行函数,编译器会报无匹配函数错误3)寻找最佳匹配
		寻找形参类型与实参类型最匹配的那个函数
		最佳匹配等级:
			1.精确匹配
					实参类型和形参类型相同
					实参从数组类型或函数类型转换成对应的指针类型
					向实参添加顶层const或者从实参中删除顶层const
			2.经过const转换实现匹配(底层const3.经过类型提高实现的匹配
			4.经过算术类型转换或指针转换实现的匹配
			5.经过类类型转换实现的匹配
	(若是重载函数的区别只是多了个底层const的话,将从函数调用的实际参数类型(常量或者很是量)来判断)
	多个形参的函数匹配
    	1.该函数每一个实参的匹配都不劣于其余可行函数须要的匹配
    	2.至少有一个实参的匹配优于其余可行函数提供的匹配
    若是检查了以后没有找到惟一的一个函数脱颖而出,则编译器报告二义性调用的信息。
 //f(42,2.56)
 //典型的二义性错误
复制代码

5.6 函数指针

​ 函数指针指向的是函数不是对象。

int max(int a,int b);
//声明一个能够指向该函数的指针,只须要用指针替换函数名便可
int (*p)(int ,int);
//将函数赋值给函数指针的时候能够忽略取地址符
p=max;
p=&max;		//加不加都同样
//调用函数指针指向的函数的时候用不用解引用指针也同样
cout<<p(1,2)<<endl;
cout<<(*p)(1,2)<<endl;
//能够为函数指针赋值0或者nullptr表示没有指向任何位置
//当使用重载函数的时候,上下文必须清晰的界定到底使用的是哪一个函数,不能够一对多
复制代码
相关文章
相关标签/搜索