1、函数
函数是将段经常使用的代码封装起来,减少重复代码量。
C++函数
语法:
返回值类型 函数名(参数列表)
{
函数体语句
return 表达式
}
下面示例包含了函数声明、函数定义、函数调用、函数形参与实参、参数值传递、函数常见样式(无参无返、无参有返、有参无返及有参有返)。
#include<iostream>
using namespace std;
//定义函数(参数为形参):两个整数相加(函数定义在调用前面,否则报错,也可以先定义函数声明,函数写在调用函数后面,参见下面的函数声明max函数)
int add(int a, int b)
{
int sum = a + b;
return sum;
}
//定义函数(值传递):交换两个数值(参数值传递,形参发生改变不影响实参)
void swap(int a, int b)
{
cout << "交换前形参:a = " << a << " , b = " << b << endl;
int tmp = a;
a = b;
b = tmp;
cout << "交换后形参:a = " << a << " , b = " << b << endl;
}
//函数声明:提前告诉编译器函数的存在,在定义前调用函数不会报错
//函数声明可以写多次(不建议写多次),但是定义只能写一次
int max(int a, int b);
int max(int a, int b);
//函数常见样式
//1、无参无返
void func1() {
cout << "这是一个无参无返回值函数" << endl;
}
//2、有参无返:参见上面的swap函数
//3、无参有返
string func3()
{
return "这是一个无参有返回值函数,这是返回的字符串";
}
//4、有参有返回,参见上面的add函数
int main()
{
//调用函数 - 两数相加(参数为实参)
cout << "调用函数:两数相加:add(5, 3) = " << add(5, 3) << endl;;
cout << "--- 参数值传递,形参发生改变不影响实参 ---" << endl;
//调用函数 - 交换两数(值传递)
int x = 5;
int y = 3;
swap(5, 3);
cout << "主函数调用交换函数(值传递)实参值, x = " << x << " , y = " << y << endl;
//调用函数 - 无参无返
func1();
//调用函数 - 无参有返
cout << func3() << endl;
//调用声明函数
cout << "调用函数声明函数max = " << max(3, 5) << endl;
system("pause");
return 0;
}
//函数定义(函数已在调用前声明)
int max(int a, int b)
{
return a > b ? a : b;
}
输出结果
调用函数:两数相加:add(5, 3) = 8
--- 参数值传递,形参发生改变不影响实参 ---
交换前形参:a = 5 , b = 3
交换后形参:a = 3 , b = 5
主函数调用交换函数(值传递)实参值, x = 5 , y = 3
这是一个无参无返回值函数
这是一个无参有返回值函数,这是返回的字符串
调用函数声明函数max = 5
Go语言函数
Go语言函数与C++函数区别:
- 函数声明与定义一起,且不区别函数定义的位置
- 可以包含多个返回值
package main
import "fmt"
func main() {
fmt.Println("调用函数:两数相加:add(5, 3) = ", add(5, 3))
fmt.Println("--- 参数值传递,形参发生改变不影响实参 ---")
x , y:= 5, 3
swap(x, y)
fmt.Printf("主函数调用交换函数(值传递)实参值, x = %d, y = %d\n", x, y)
fmt.Println("--- 实参通过接收函数返回值交换数据 ---")
x, y = swap1(x, y)
fmt.Printf("调用函数可以有多个返回值(返回值写法1 - 返回值没有定义名称) - 实现两数交换: x = %d, y = %d\n", x, y)
x, y = swap1(x, y)
fmt.Printf("调用函数可以有多个返回值(返回值写法2 - 返回值定义名称) - 实现两数交换: x = %d, y = %d\n", x, y)
}
//定义函数(参数为形参)
func add(a int, b int) int {
return a + b
}
//定义函数(值传递):交换两个数值(参数值传递,形参发生改变不影响实参)
func swap(a int, b int) {
fmt.Printf("交换前形参:a = %d, b = %d\n", a, b)
a, b = b, a
fmt.Printf("交换后形参:a = %d, b = %d\n", a, b)
}
//函数可以有多个返回值(返回值写法1 - 返回值没有定义名称):交换两个数
func swap1(a int, b int) (int, int) {
return b, a
}
//函数可以有多个返回值(返回值写法2 - 返回值定义名称):交换两个数
func swap2(a int, b int) (x int, y int) {
x, y = b, a
return
}
输出结果
调用函数:两数相加:add(5, 3) = 8
--- 参数值传递,形参发生改变不影响实参 ---
交换前形参:a = 5, b = 3
交换后形参:a = 3, b = 5
主函数调用交换函数(值传递)实参值, x = 5, y = 3
--- 实参通过接收函数返回值交换数据 ---
调用函数可以有多个返回值(返回值写法1 - 返回值没有定义名称) - 实现两数交换: x = 3, y = 5
调用函数可以有多个返回值(返回值写法2 - 返回值定义名称) - 实现两数交换: x = 5, y = 3
2、函数分文件编写
可以把上面的交换函数swap放在一个公共文件中,供其他文件调用。
C++ 分文件编写
(1)创建.h头文件
在解决方案中,右键单击“头文件” -> 选择“添加” -> 选择“新建项”,如下图所示:
选择“头文件” -> 修改文件名称(.h结尾) -> 单击“添加”按钮,如下图所示:
(2)在.h头文件声明函数
#include <iostream>
using namespace std;
//两数交换函数声明
void swap(int a, int b);
(3)创建.cpp源文件
在源文件中创建swap.cpp文件,与创建头文件几乎相同,在学习(一)时已经演示过了,此处不再赘述。
(4)在.cpp源文件中定义函数
在swap.cpp文件中,引用头文件swap.h,即与其关联,代码如下所示:
#include "swap.h"
//定义函数(值传递):交换两个数值(参数值传递,形参发生改变不影响实参)
void swap(int a, int b)
{
cout << "交换前形参:a = " << a << " , b = " << b << endl;
int tmp = a;
a = b;
b = tmp;
cout << "交换后形参:a = " << a << " , b = " << b << endl;
}
(5)测试主函数调用(另一个.cpp文件)
创建一个新的.cpp文件,引.h入头文件,在main函数中调用头文件中的swap函数,文件结构如下:
调用函数文件代码如下:
#include<iostream>
#include "swap.h"
using namespace std;
int main()
{
//调用头文件中声明的函数
cout << "调用头文件中声明的函数 swap(5, 3) " << endl;;
swap(5, 3);
system("pause");
return 0;
}
输出结果
调用头文件中声明的函数 swap(5, 3)
交换前形参:a = 5 , b = 3
交换后形参:a = 3 , b = 5
Go语言调用其它包中的函数
(1)创建公共函数
新建一个文件夹 “19-函数-公用函数”, 此处作为演示使用,实际项目中不建议使用中文名命名文件或文件夹。在该文件夹中创建一个.go文件(common.go),定义函数如下:
package common
import "fmt"
//定义函数(值传递):交换两个数值(参数值传递,形参发生改变不影响实参)
func Swap(a int, b int) {
fmt.Printf("交换前形参:a = %d, b = %d\n", a, b)
a, b = b, a
fmt.Printf("交换后形参:a = %d, b = %d\n", a, b)
}
注:在Go语言中,若想函数被其它包能够访问,函数名首字母需要大写(其含义为其它语言中的public)
(2)调用公共函数
创建主文件.go,调用公共函数(Swap),文件结构如下图所示:
源码如下:
package main
import (
"fmt"
common "testProject/CPlus/19-函数-公用函数"
)
func main() {
fmt.Println("调用公共函数 swap(5, 3)")
common.Swap(5, 3)
}
输出结果
调用公共函数 swap(5, 3)
交换前形参:a = 5, b = 3
交换后形参:a = 3, b = 5
3、函数默认参数
C++函数默认参数
函数参数可以设置默认值,调用时若传递了数据,则使用传递的数据,否则使用默认值。
注:
- 函数参数中,如果某个位置有默认值,那么这个位置之后的参数都要有默认值
- 声明与实现只能有一个能包含参数默认值;如果函数声明有参数默认值,函数实现时就不能有参数默认值,反之亦然。
#include<iostream>
using namespace std;
//声明与实现只能有一个能包含参数默认值,举个例子声明无默认值,实现有默认值
int add(int a, int b, int c);
//int add(int a, int b = 10, int c = 3); //报错:重定义默认参数
//参数默认值:调用时若传数据,则使用传递的数据,否则使用默认值
//如果某个位置有默认值,那么这个位置之后的参数都要有默认值
int add(int a, int b = 10, int c = 3)
{
int sum = a + b + c;
return sum;
}
int main()
{
//函数 - 默认参数
cout << "调用时传递了所有参数,结果为:" << add(5, 10, 3) << endl;
cout << "调用时传递了2个参数,结果为:" << add(5, 10) << endl;
cout << "调用时传递了1个参数,结果为:" << add(5) << endl;
system("pause");
return 0;
}
//函数定义(函数已在调用前声明)
int max(int a, int b)
{
return a > b ? a : b;
}
输出结果
调用时传递了所有参数,结果为:18
调用时传递了2个参数,结果为:18
调用时传递了1个参数,结果为:18
Go语言函数中没有默认参数
4、函数占位参数
C++函数占位参数
C++中函数的形参列表可以有占位参数,用作占位,调用函数时必须填补该位置。占位参数可以有默认值。
语法:返回值类型 函数名(数据类型) { 函数体 }
#include<iostream>
using namespace std;
//函数 - 占位参数:占位参数可以有默认值
void f1(int a, int = 9)
{
cout << "函数参数 a = " << a << endl;
}
int main()
{
//函数 - 占位参数
//调用函数占位参数
f1(5, 3);
system("pause");
return 0;
}
//函数定义(函数已在调用前声明)
int max(int a, int b)
{
return a > b ? a : b;
}
输出结果
函数参数 a = 5
Go语言函数中没有占位参数
5、函数重载
C++函数重载
函数名相同,提高复用性。
函数重载条件:
- 同一个作用域下
- 函数名相同
- 函数参数类型不同,或参数个数不同,或参数顺序不同
函数返回值不作为函数重载条件,即返回值要相同。
注意:
- 引用作为重载条件的使用
- 函数重载遇到默认参数,会出现二义性,因此避免重载时有默认参数的情况
#include<iostream>
using namespace std;
//函数 - 函数重载 : 同作用域下同名函数,函数参数类型不同,或参数个数不同,或参数顺序不同
void f1()
{
cout << "函数 f1 无参" << endl;
}
//参数个数不同
void f1(int a)
{
cout << "函数 f1(int a) 有一个整型参数" << endl;
cout << "a = " << a << endl;
}
//参数类型不同
void f1(string a)
{
cout << "函数 f1(string a) 有一个字符串类型参数" << endl;
cout << "a = " << a << endl;
}
//参数顺序不同
void f1(int a, string b)
{
cout << "函数 f1(int a, string b) 有2个参数,第1个整型,第2个字符串类型" << endl;
cout << "a = " << a << ", b = " << b << endl;
}
void f1(string a, int b)
{
cout << "函数 f1(string a, int b) 有2个参数,第1个字符串类型,第2个整型" << endl;
cout << "a = " << a << ", b = " << b << endl;
}
//引用作为重载条件
void f2(int& a)
{
cout << "函数 f2(int& a) 有一个引用整型参数" << endl;
cout << "a = " << a << endl;
}
void f2(const int& a)
{
cout << "函数 f2(const int& a) 有一个常量引用参数" << endl;
cout << "a = " << a << endl;
}
//函数重载遇到默认参数
void f3(int a)
{
cout << "函数 f3(int a) 有一个整型参数" << endl;
cout << "a = " << a << endl;
}
void f3(int a, int b = 3)
{
cout << "函数 f3(int a, int b = 3) 有2个整型参数,第2个参数有默认值" << endl;
cout << "a = " << a << ", b = " << b << endl;
}
int main()
{
//函数 - 函数重载
//调用重载函数
f1();
f1(5);
f1("Hello");
f1(5, "Hello");
f1("Hello", 5);
cout << endl << " --- 引用作为重载条件 --- " << endl << endl;
//调用重载函数 - 引用参数
int a = 7;
f2(a);
f2(7);
cout << endl << " --- 函数重载遇到默认值 --- " << endl << endl;
//函数重载遇到默认值
//f3(5); //此处出现二义性,报错,尽量避免函数重载中有默认值的情况
f3(5, 7);
system("pause");
return 0;
}
//函数定义(函数已在调用前声明)
int max(int a, int b)
{
return a > b ? a : b;
}
输出结果
函数 f1 无参
函数 f1(int a) 有一个整型参数
a = 5
函数 f1(string a) 有一个字符串类型参数
a = Hello
函数 f1(int a, string b) 有2个参数,第1个整型,第2个字符串类型
a = 5, b = Hello
函数 f1(string a, int b) 有2个参数,第1个字符串类型,第2个整型
a = Hello, b = 5--- 引用作为重载条件 ---
函数 f2(int& a) 有一个引用整型参数
a = 7
函数 f2(const int& a) 有一个常量引用参数
a = 7--- 函数重载遇到默认值 ---
函数 f3(int a, int b = 3) 有2个整型参数,第2个参数有默认值
a = 5, b = 7
Go语言函数中没有函数重载
Go 语言的设计理念就是 “显式大于隐喻”,追求明确,显式。
函数重载和参数默认值有隐喻的含义。调用者只看函数名,可能没法知道这个默认值,又或是入参不同等,C++函数重载有默认值时,会出现二义性(见上例),Go语言避免这样的情况发现,因此Go语言中没有函数重载与默认值。