小古银的官方网站(完整教程):http://www.xiaoguyin.com/
C++入门教程视频:https://www.bilibili.com/video/av20868986/
目录
前言
本部分教程将详细讲解函数和其他非常常用的函数相关的知识。
本部分教程的目的:
- 详细函数的细节。
- 讲解非常常用的函数相关的知识。
没有返回值的函数
并不是所有的功能都有运算结果,也就是说,并不是所有的函数都有返回值。返回类型是void
的函数不需要返回值,并且可以省略不写return;
。
例如,我有一个函数,专门用来输出提示信息的。
#include <iostream>
void print_tips(void)
{
std::cout << "************************************************" << std::endl;
std::cout << "* 小古银的C++教程 *" << std::endl;
std::cout << "* 新手专用的教程 *" << std::endl;
std::cout << "* 有了它,你不在烦恼入不了门 *" << std::endl;
std::cout << "* 有了它,你的头发将会和我一样加了特效 *" << std::endl;
std::cout << "* C++圈里面个个都是人才,说话又好听 *" << std::endl;
std::cout << "* 右边就是对不齐 *" << std::endl;
std::cout << "************************************************" << std::endl;
}
int main(void)
{
print_tips();
return 0;
}
注意:没有返回值不代表不返回,有不少的情况还是需要写return;
的。
返回多个值的函数
现在写一个整数除法的函数,返回商和余数。这样就要返回两个值了。当需要返回两个值时,此时,返回类型就必须是std::tuple
。
基础示例
#include <iostream>
#include <tuple>
// 除法运算
// 参数: a 被除数
// 参数: b 除数, 该参数不能传入0
// 返回值: 商和余数
std::tuple<int, int> dividedby(int a, int b)
{
return { a / b, a % b };
}
int main(void)
{
auto [quotient, remainder] = dividedby(15, 4);
std::cout << "商:" << quotient << std::endl;
std::cout << "余数:" << remainder << std::endl;
return 0;
}
输出结果:
商:3
余数:3
基础讲解
注意:调用别人的函数时,一定要看函数的说明文档,像上面定义的函数是有前提条件的:除数不能传0
。
由于int
和int
的运算也是int
,所以a / b
就是计算结果的整数部分(如:9除以2的结果就是整数4)。而a % b
求出余数。然后将它们用{}
装起来作为std::tuple
的初始值,然后返回std::tuple
对象。
用变量保存返回值时则必须使用关键字auto
,然后在[]
里面写需要被赋值的变量,然后返回的std::tuple
对象就会对[]
里面的变量逐一初始化。
返回类型推导
当使用关键字auto
作为函数的返回类型时,编译器可以根据返回值去确定返回类型,如果使用了return;
或者没有return
,那么返回类型就是void
。
注意:
- 如果返回值是用
{}
括起来的数据组合,那么编译器将推导不出返回类型,因为非常多的类型都可以使用{}
。 - 如果用
auto
作为函数的返回类型,那么只有当函数定义写在调用者前面的时候,编译器才能根据返回值进行推导。而实际工程中,函数定义一般都是对调用者不可见(因为函数定义放在其他源文件中)。因此,实际工程中只有模板能用这个特性。
基础示例
#include <iostream> // std::cout std::endl
auto power(int a, int b)
{
if (b == 0)
{
return static_cast<double>(1);
}
double result = a;
for (int i = 1; i < std::abs(b); ++i)
{
result *= a;
}
return b < 0 ? (1 / result) : result;
}
int main(void)
{
std::cout << power(2, 10) << std::endl;
std::cout << power(10, -1) << std::endl;
return 0;
}
基础讲解
函数power()
用于求a
的b
次方。只有当返回值类型都是一样的时候,编译器才能推导出返回类型。假设上面代码不转换1
的类型而直接写return 1;
,那么编译时就会报错,因为返回类型不一样。
没有参数
当一个函数没有参数时,那么函数名称后的()
内就不需要填任何东西,也可以填一个void
代表没有参数。例如:void print();
或者void print(void);
,它们是等价的。
不过我个人习惯是在()
里面写void
,所以在我的教程中,无参数的函数都是这样写的。
无名参数
有时候的重载函数需要用参数区分,但是用以区分的参数实际上在函数定义中没有作用。当局部变量没有被使用时,编译器一般会报警告,这个时候,就可以只写参数类型而不写参数名称,这就是无名参数。例如void print(int, int);
,函数定义也不需要写参数名称。
默认实参
当函数有一个参数需要用户提供,但是这个参数经常是某个值而且不需要求改,那么就可以用默认实参。
注意:
- 有默认实参的参数必须在没有默认实参的参数后面。
- 默认实参只写在函数声明中,不能写在函数定义中。
基础示例
#include <iostream> // std::cout std::endl
#include <cmath> // std::abs
double power(int a, int b = 2);
int main(void)
{
std::cout << power(100) << std::endl; // 当不填写第二个参数时, 则默认第二个参数是2
std::cout << power(2, 10) << std::endl;
std::cout << power(10, -1) << std::endl;
return 0;
}
double power(int a, int b)
{
if (b == 0)
{
return static_cast<double>(1);
}
double result = a;
for (int i = 1; i < std::abs(b); ++i)
{
result *= a;
}
return b < 0 ? (1 / result) : result;
}
输出结果:
10000
1024
0.1
补充知识(了解即可)
返回多个值的函数从C++17开始加入。
C++11引入返回类型后置。例如:
auto get(void) -> int;
,将数据类型放到函数后面。C++14开始引入返回类型推导,并且允许省略后置的类型,那么前面的代码就可以简写成:auto get(void);
;