【C++学习记录】函数、链接器与函数的声明和定义、函数默认参数、函数重载、内联函数
函数
定义:编写的代码块,被设计用来执行特定的任务。
函数在类中被称作方法(methods)
主要目的:防止大量代码重复。在需要复制粘贴大量代码的地方改为使用函数可提高效率、减少错误。
太多的函数调用会减慢运行速度(非内联(inline)函数时):每次调用函数,编译器产生一个调用指令。
为了调用一个函数,需要为该函数创建一个栈框架(stack frame),将参数、返回地址等推(push)到栈上;然后跳到程序的相应位置,执行那个函数;函数执行完后返回保存在栈上的数据,回到调用函数的地方。
因此反复地调用函数会减慢程序的运行速度。
在使用if-else分支语句时,执行的代码会随着分支条件的判断而跳转,如果“语句和分支条件分布在内存距离较远的地方”,代码会比较低效,所以很多优化过的代码会避免分支结构。
不论是传值方式或是传地址(指针或引用)方式,都可以看做形参在栈内存中开辟了新的空间并复制了实参的值。因为传地址方式传递的是地址(而地址通常不是用户所关心的数据),所以函数体内可以通过对地址的解引用操作修改实参的值。
函数可以重复声明,不可重复定义。所以通常在头文件(.h)中存放声明,在cpp文件中存放定义。
链接器(linker)的工作方式
在main()中调用一个函数func()时:
如果main.cpp文件(存放main函数的文件)中没有func()函数的声明和定义,会直接报错“未定义标识符(编译错误,C开头)”。在该文件中添加func()函数的声明后,文件单独编译成功(ctrl+F7)。
如果在该项目的其他cpp文件中没有func()函数的定义,则在生成项目(ctrl+b)时报错“无法解析的外部命令(链接错误,LNK开头)”。
为什么声明了一个函数即使没有定义,也能编译成功?
声明func()函数相当于告诉编译器:“这个项目中的某一个文件中存在一个名为func()的函数定义,而我将要用到它。”编译器完全“相信了”我们的鬼话,所以单独编译(compile)一个文件时不会报错。
而当生成(build)整个项目时,链接器会根据main()函数中调用的func()函数的声明在整个项目中寻找func()函数的定义,然后将主文件中的调用链接起来;如果找不到func()函数的定义,就会发生链接错误(linking error)
函数的默认参数
可以在声明中或定义中设置默认参数,二者选一,不能同时在二者中设置默认参数。
默认参数从右往左定义,调用函数时传入的参数则从左往右赋值。
注意事项:
1、在声明中使用默认参数时可省略形参名
void func(int = 111, int = 222);
void func(int x, int y)
{
cout << "first: " << x << " second: " << y << endl;
}
2、可以使用全局变量作为默认参数
int x = 111;
void func(int = x, int = 222);
void test()
{
int x = 333;
func();
}
test函数输出的值为111和222,func函数的默认值在声明中已经设置好了,不会受test的成员变量x影响
3、当调用一个使用了默认参数的函数时,默认参数的必须在调用该函数前设置好(上例),否则编译器无法知道默认参数的存在
void func(int,int);
void test()
{
int x = 333;
func();
}
void func(int x = 111, int y = 222)
{
cout << "first: " << x << " second: " << y << endl;
}
编译失败。“必须为func函数传入2个int类型数据”
函数重载
同名函数,编译器通过参数类型或参数个数分辨不同的重载版本。
使用默认参数的重载函数会“减少参数个数”,可能引发编译错误。
对于const参数:
普通变量
void func(int i){}
void func(const int i) {}
//无法区分函数
引用
void func(int& i){} //①
void func(const int& i) {} //②
//可以区分
int a = 1;
func(a);//传入变量,调用①
func(1);//传入常量,调用②
指针
void func(int* i){} //①
void func(const int* i){} //②
void func(int* const i){} //③
//①与③会引发冲突:“函数“void func(int *)”已有主体”
//将函数定义③删除后:
int a = 1;
int* p1 = &a;
const int* p2 = &a;
int* const p3 = &a;
func(p1); //调用①
func(p2); //调用②
func(p3); //调用①
内联函数inline
目前能理解的部分:定义为内联函数的函数在被调用时,整段函数代码被粘贴到函数被调用的位置。
使用内联函数能避免一般函数调用时的压站退栈开销,很适合经常使用的的小型函数。
编译器有时会忽略内联修饰符,将其修饰的函数作为普通函数处理。
函数的返回值为引用类型(暂时还不知道用处,先记着)
int& func()
{
int a = 10;
return a;
}
int& a = func();
int b = func();
cout << a << " " << b << endl;
cout << a << " " << b << endl;
cout << a << " " << b << endl;
输出结果:
10 10
2027202960 10
2027202960 10
变量a的数据在被保留一段时间后被释放。
函数的调用也可以作为左值
int& func()
{
static int a = 10;
return a;
}
cout << func() << endl;
func() = 20;
cout << func() << endl;
//输出 10
20
上一篇: 完美运动框架
下一篇: JS函数定义和设置默认参数默认值