C++基础02(函数)
文章目录
- 函数function
- 内置函数
- 函数重载
- 可以形成重载的情形
- **不可以形成重载的情形**
- 函数模板
- 关键字auto
- 函数默认参数
函数function
1.函数的概念:为了实现特定功能所组织起来代码的集合
2.函数的作用:1.代码复用2.分解过程
3.函数的定义格式:
返回类型 函数名([形参列表])
{
函数体
}
4.函数调用格式:函数名([实参列表]);
5.函数的分类:
根据有无形参:有参函数,无参函数
根据返回值:有返回值函数和无返回值函数
从作用域角度:内部函数static 外部函数
从用户的角度:系统函数,自定义函数
6.函数的返回值
函数返回结果,可以通过return这个关键字实现值的返回,一次只能返回一个。
return:返回一个值
终止当前函数
如果希望函数向外界返回多个结果:通过指针类型的形参进行返回,return配合输出型形参,全局变量,把多个值封装在一个结构体进行返回
内置函数
目的:提高程序的执行效率(省略了函数调用时的现场包含和回复现场的动作语句)
调用函数时需要一定的时间和空间的开销。如图为函数调用的过程:
C++提供一种提高效率的方法,即在编译时将所调用函数的代码直接嵌入到主调函数中,而不是将流程转出去。这种嵌入到主调函数中的函数称为内置函数(inline function),又称内嵌函数。有称为内联函数。
指定内置函数的方式 为:在函数首行的左端加一个关键字inline即可。
#include<iostream>
#include<iomanip>
using namespace std;
int add(int a, int b);//对于内联函数,在声明时可以加inline关键字 也可以省略。
//内置函数的使用场景:某个函数在程序中被频繁调用,且该函数的语句没有超过5句的情况下,此时该函数就适合定义为内置函数
//inline关键字要放在函数返回类型的前面 -----目的 提高程序的执行效率 (省略了函数调用时的现场包含和恢复现场的动作语句)
inline int add(int a, int b) //被inline关键字修饰的函数 我们称为内置函数,内联函数或内嵌函数
{
return a + b;
}
int main()
{
//一个函数一旦被标定为内联函数,此时在堆该函数的调用语句编译时,会将该函数的函数体语句替换该调用语句
int ret= add(10, 20);//内联函数的调用可以像普通函数一样去调用 10+20
cout << ret << endl;
return 0;
}
注意:
可以在声明函数和定义函数时同时写inline,也可以只在其中一处声明inline,效果相同,都能按内置函数处理。
使用内置函数可以节省运行时间,但却增加了目标程序的长度,因此一般只将规模很小(一般为5个语句一下)而使用频繁的函数(如定时采集数据的函数)声明为内置函数。
内置函数中不能包括复杂的控制语句,如循环语句和switch语句。
应当说明:对函数作inline声明,只是程序设计者对编译系统提出的一个建议,也就是说它是建议性的,而不是指令性的。并非一经指定为inline,编译系统就必须这样做。编译系统会根据具体情况决定是否这样做。
归纳起来,只有那些规模较小而又被频繁调用的简单函数,才适合声明为inline函数。
函数重载
在C语言中,相同作用域内的重名函数会引起冲突,哪怕它们拥有不同的参数列表也不行,而在C++中,重名函数只要满足一定的要求,可以同时存在,这大大拓展了函数设计的灵活性。这种重名且可并存的语法机制,被称为函数重载
C++中大量存在重载的函数,这些同名函数实际上就是一个函数的不同版本。比如,C++中的标准字符串类型 string 中的构造函数拥有 6 个不同的版本
string ( const string& str );
string ( const string& str, size_t pos, size_t n = npos );
string ( const char * s, size_t n );
string ( const char * s );
string ( size_t n, char c );
这些名称相同的函数,都存在于同一名字空间中,怎样才能形成合理合法的重载而不会冲突呢?这个问题的答案比较复杂,总体的基本原则是,只要让系统在使用它们的时候,可以有效地区分各个不同的版本,那它们就可以形成合法的重载版本
示例1:
#include<iostream>
#include<iomanip>
using namespace std;
//下边这两个函数能重载成功,原因在于类型不一样
void add(const int* a)
{
cout << "two int1" << endl;
}
void add(int* a)
{
cout << "two int" << endl;
}
int main()
{
const int a = 10;
add(&a);
return 0;
}
可以形成重载的情形
- 参数个数不同
- 参数类型不同
- 类方法(即类内部的函数)的
const
属性可以构成重载 - 普通指针与常目标指针可以构成重载
示例2:
#include<iostream>
#include<iomanip>
using namespace std;
//函数重载:就时在同一个作用域下,定义多个同名函数,但是要确保这些函数之间的参数个数或类型不相同
int add(int a, int b)
{
cout << "two int" << endl;
return a + b;
}
int add(int a, int b,int c) //这个函数确保的是函数之间参数个数不一样
{
cout << "three int" << endl;
return a + b+c;
}
float add(float a, float b) //与第一个相比,是类型不一样
{
cout << "float" << endl;
return a + b;
}
string add(string a, string b) //函数重载能否成功 和函数的返回类型是没有关系
{
cout << "string" << endl;
return a + b;
}
int main()
{
add(10, 20);//对于重载函数的调用,它会根据调用语句所提供的实参类型或个数来匹配对应的函数
add("baozhang", "tongzuo");
return 0;
}
不可以形成重载的情形
- 函数名、函数参数列表完全一致。
- 函数的返回值类型差异。
- 静态函数声明(static)。
- const型变量(包括常指针)。
示例代码:
// 函数名、参数列表完全一致,仅靠返回值类型
// 的差异,将无法形成重载,这两个函数将会冲突
void f1(int a);
float f1(int a);
// static不能形成重载,以下两个函数将会冲突
int f2(int a);
static int f2(int a);
// const型变量(包括常指针),不能形成重载
void f3( int a);
void f3(const int a);
void f4(char *p);
void f4(char *const p);
函数模板
所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能
示例:
#include <iostream>
using namespace std;
// 函数模板的定义
template <typename T> // 这里的T代表一个虚拟的类型
T add(T a, T b) // 声明的虚拟类型可以在函数的返回类型,形参类型和函数体中来使用
{
return a + b;
}
int main(int argc, char const *argv[])
{
cout << add(10,20) << endl;
cout << add(10.2,20.3) << endl;
cout << add('a','b') << endl;
return 0;
}
可以看到,用函数模板比函数重载更方便,程序更
简洁。但应注意它只适用于函数的参数个数相同而
类型不同,且函数体相同的情况,如果参数的个数
不同,则不能用函数模板。
关键字auto
在C语言中,auto
用来声明一个存储在栈的变量,因此它只能用来修饰临时变量,不能用来修饰全局变量、静态变量,与此同时临时变量本身默认就是存储在栈中,因此在C语言中,auto
基本上是作废的。
在C++中,auto
代表自动获得数据的类型,比如:
auto a = 100; // 等价于: int a = 100;
然,上述代码仅是语法示例,无法体现 auto
的价值,在C++的函数模板、类模板中,利用 auto
自动获得数据类型,往往有奇效,例如:
// 以下函数是一个模板,接收一个类型为 T 的容器
// 注意:类型 T 是动态的,可变的,不定的。
template <typename T>
void show(T &container)
{
// 利用 auto 动态获取未知类型容器的相关数据
auto it = container.begin();
...
...
}
函数默认参数
C++允许一个函数的参数有默认值,例如:
// 函数的声明
// 右侧的参数 b 如果没有传递,则默认值为3.14
void f(int a, float b = 3.14);
int main()
{
// 显式给 b 传递参数1.23
f(100, 1.23);
// 使用 b 的默认值3.14
f(200);
}
语法要点
- 为了防止出现二义性,具备默认值的参数只能位于参数列表的最右边
- 如果函数定义与函数声明不在同一文件,一般只为声明指定默认参数,定义处不写默认参数