第六章:函数

一:函数基础

        形参和函数内部定义的变量统称为局部变量

        局部静态对象使用static关键字,当程序执行到变量定义处生成该变量并且初始化,直到程序结束才被销毁,在此期间即使变量所在的函数调用结束该变量也还在。例如下图的ctr就是定义的局部静态变量。

  

        函数声明也称为函数原型,描述了函数的三要素:返回类型函数名形参类型

二:参数传递

        在c语言中,访问函数外部对象用指针传递,在c++中建议使用引用传递。

        当函数无需修改形参的值时候,建议使用常量引用传递。

        如果形参不需要改变实参的值,就将其设为常量引用,因为普通引用可能会有修改实参的风险并且普通引用做形参会使得字面值常量和const类型对象无法做实参调用该函数,大大的限制了函数的使用。

三:数组形参

        1.使用结束标记,如下图的代码所示

        2.使用迭代器,如下图所示。调用时候,print(begin(a), end(a)),这里a是数组。

        3.把数组大小作为参数传递进去。

四:main函数的参数

        main函数的带参数形式如下,argv是一个数组,每个元素指向一个c风格字符串。argc表示数组中字符串的数量。

int main(int argc, char *argv[])

        假设prog文件中有main函数,在命令行执行“prog -d -o ofile data0”,则argc的值为5,argv的内容如下图所示:

五:含有可变形参的函数。

        使用initializer__list类型。具体应用如下面的代码所示。和vector类型很像,不过也有区别,具体区别见以下博客https://www.jianshu.com/p/3d69ff89a0c9     c++的列表是initializer_list类型的,该类型不能修改元素。可以用数组和vector初始化inistializer_list类型。例如initializer_list<int> li(vi.begin(), bi.end()),这里vi是vector<int>类型。

#include<iostream>
#include <initializer_list>
#include<vector>
using namespace std;
int sum(initializer_list<int> li)
{
	int sum = 0;
	for (auto &i : li)
	{
		sum += i;
	}
	return sum;
}
int main(int argc, char *argv[])
{
	initializer_list<int> li = { 1,2,3,4,5 };
	int k = sum(li);
	cout << k << endl;
	while (1) {}
	return 0;
}

六:函数返回左值

        当函数返回的是引用类型的时候,返回的是左值。这时候如果返回的是常量引用类型,可以用于赋值语句。如下面代码所示,程序将输出hEllo,dear。

#include<iostream>
#include <string>
using namespace std;
char &get_val(string &s, int index)
{
	return s[index];
}
int main(int argc, char *argv[])
{
	string s = "hello,dear";
	get_val(s, 2) = 'E';
	cout << s << endl;
	return 0;
}

七:返回指向数组的指针

        可以用 int *fun()[10]返回一个指针,该指针指向大小为10的数组。也可以用尾置返回类型auto fun() -> int (*)[10]。

八:函数重载

        当两个函数可以接受相同的实参时候就不是重载了。所以顶层const修饰的变量不是重载,例如下图的四个函数的定义。

因为无论输入的实参是常量还是非常量,都没法区分开该调用哪个函数。

        但是如果是底层const,就可以实现重载的。如下图所示的函数定义,当传入一个指向常量的指针或者引用的时候,就会找到形参是const版本的函数,另一个非const版本是没法接受指向常量的指针或引用作为实参的。当传入一个指向非常量的指针或者引用时候,两个版本的函数的形参都能接受实参,不过会优先选择非const的版本。

        在内层作用于定义同名函数会隐藏外层的函数。如下图内层的print会覆盖外层的print函数。

九:默认参数

#include<iostream>
#include <string>
using namespace std;
int n_para = 0;
string s_para = "before_change";
void print(int n = n_para, string s = s_para)
{
	cout << n << " " << s << endl;
}
int main(int argc, char *argv[])
{
	print();
	s_para = "after_change";
	n_para = 10;
	print();
	int n_para = 100;
	print();
	while (1) {}
	return 0;
	
}

 

输入如下

0 before_change
10 after_change
10 after_change

        在主函数里面修改s_para和n_para后,调用函数时候,才具体求值然后给形参初始化,所以第二次调用输出10, after_change。但是在主函数中重新定义同名变量n_para后,隐藏了原来的n_para,但是函数用到的实参是原来定义的n_para,所以第三次调用输出仍然是10而不是100;

十:匹配函数

        一:选出候选函数:1.与被调用的函数同名。2.在调用点函数可见。

        二:选出可行函数:1.形参数量与提供的实参数量相等。2.每个实参的类型与对应的形参类型相同,或者能够通过类型转换转化为形参类型。

        三:寻找最佳匹配:若函数满足1.该函数每个实参的匹配都不劣于其他可行函数的匹配。2.该函数至少有一个实参的匹配优于其他可行函数的匹配。例如对下面所示的代码,编译会报错:有多个重载有相似的转换。

#include<iostream>
using namespace std;
void f(int a, int b)
{
	cout << a + b << endl;
}
void f(double a, double b)
{
	cout << a - b << endl;
}
int main(int argc, char *argv[])
{
	f(1.3, 1);	
	return 0;	
}

十一:函数指针

        一.函数类型:函数类型由他的返回类型和形参类型决定,与函数名无关。例如bool lengthCompare(const string &s1, const string &s2),该函数的类型是bool (const string &, const string &)。

        二.定义一个函数指针的语句为 bool (*p)(const string &, const string &)。

        三.为函数指针赋值的语句可以是以下两种: 这里,取地址符可选。

    p = lengthCompare;
	p = &lengthCompare;

        四.通过函数指针调用调用函数可以是以下两种。

	bool b = p("hello", "hi");
	bool c = (*p)("hello", "hi");

        五.函数指针可以作为函数的形参。

猜你喜欢

转载自blog.csdn.net/qq_25974431/article/details/86611028