C++学习第八课:函数的高级使用
在C++中,函数是封装一段代码的单元,使得代码更加模块化、重用性高,并且易于维护。本课我们将介绍如何使用函数组织代码,包括函数原型、定义、调用、参数传递、返回值、默认参数值、递归函数、多返回值函数、函数重载、数组传递、引用传递、内联函数和lambda函数。
为什么需要函数
- 模块化:将大问题分解成小的、可管理的部分。
- 重用性:避免重复代码,提高代码的可读性。
- 维护性:便于修改和测试。
函数原型和定义
函数原型指明了函数的返回类型、名称和参数列表。函数定义包含了函数的完整实现。
// 函数原型
int add(int a, int b);
// 函数定义
int add(int a, int b) {
return a + b;
}
调用函数
使用函数名和一对圆括号来调用函数,实参会被传递给形参。
int result = add(5, 10); // 调用函数并传递实参5和10
返回值
函数可以使用 return
语句返回一个值。
int square(int num) {
return num * num;
}
默认值参数
可以为函数参数提供默认值,这样在调用函数时可以省略该参数。
void print(int value, int times = 1) {
for (int i = 0; i < times; ++i) {
std::cout << value << std::endl;
}
}
递归函数
递归函数是调用自身的函数,用于解决如阶乘、斐波那契数列等问题。
int factorial(int n) {
if (n <= 1) return 1; // 基础情况
return n * factorial(n - 1); // 递归调用
}
多返回值的函数
函数可以通过输出参数(通常是引用参数)来返回多个值。
void getFactors(int num, std::vector<int>& factors) {
for (int i = 1; i <= num; ++i) {
if (num % i == 0) {
factors.push_back(i);
}
}
}
函数重载
允许定义多个具有相同名称但参数不同的函数。
void print(int num) {
std::cout << num << std::endl;
}
void print(const std::string& text) {
std::cout << text << std::endl;
}
将数组传给函数
通常通过指针或引用传递数组给函数。
void printArray(int arr[], int size) {
for (int i = 0; i < size; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
引用传递参数
使用引用参数可以避免复制,提高性能,常用于传递大型对象。
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
内联函数
使用 inline
关键字声明的函数,建议编译器在每次调用时插入该函数的代码,而不是生成函数调用的代码。
inline int max(int a, int b) {
return a > b ? a : b;
}
lambda函数
C++11引入的匿名函数,常用于编写简短的、单次使用的函数。
auto add = [](int a, int b) {
return a + b;
};
代码实例
下面是一个结合了上述概念的完整示例程序:
#include <iostream>
#include <vector>
#include <algorithm>
// 函数原型
void print(const std::string& text);
int add(int a, int b = 10);
int factorial(int n);
void swap(int& a, int& b);
void printArray(int arr[], int size);
auto getLambda();
int main() {
// 调用函数
print("Hello, World!");
int result = add(5); // 使用默认参数
std::cout << "Factorial: " << factorial(5) << std::endl;
int a = 10, b = 20;
std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;
swap(a, b);
std::cout << "After swap: a = " << a << ", b = " << b << std::endl;
int array[] = {1, 2, 3, 4, 5};
printArray(array, 5);
auto addLambda = getLambda();
std::cout << "Lambda add: " << addLambda(3, 4) << std::endl;
return 0;
}
// 函数定义
void print(const std::string& text) {
std::cout << text << std::endl;
}
int add(int a, int b) {
return a + b;
}
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
void printArray(int arr[], int size) {
for (int i = 0; i < size; ++i) {
std::cout << arr[i] << " ";
}
std::cout << '\n';
}
auto getLambda() {
return [](int a, int b) {
return a + b;
};
}
在C++中,函数重载(Function Overloading)和函数重写(Function Overriding)是两个不同的概念,它们都与多态性(Polymorphism)相关,但含义和使用场景有所不同。
函数重载(Function Overloading)
函数重载是指在同一个作用域(通常是同一个类)内,允许存在一个以上的函数名称相同,但它们的参数列表必须不同。参数列表的不同可以是参数的类型不同、参数的数量不同或者参数的顺序不同。
特点:
- 发生在同一个类中。
- 函数名相同,但参数类型、数量或顺序不同。
- 编译时多态,也称为静态多态或早期多态。
示例:
class Example {
public:
void display(int a) {
std::cout << "Int: " << a << std::endl;
}
void display(double a) {
std::cout << "Double: " << a << std::endl;
}
void display(int a, int b) {
std::cout << "Two Ints: " << a << " and " << b << std::endl;
}
};
在这个例子中,display
是被重载的函数,每个 display
函数的参数列表都不相同。
函数重写(Function Overriding)
函数重写是指在派生类(子类)中提供一个与基类(父类)中具有完全相同的名称和参数列表的函数。这是运行时多态的一个例子,因为函数调用的最终目标是在程序运行时绑定的。
特点:
- 发生在父子类之间。
- 函数名和参数列表完全相同。
- 运行时多态,也称为动态多态或晚期多态。
示例:
class Base {
public:
virtual void show() {
std::cout << "Base show" << std::endl;
}
};
class Derived : public Base {
public:
void show() override {
std::cout << "Derived show" << std::endl;
}
};
在这个例子中,Derived
类重写了 Base
类的 show
函数。
区别
- 作用域:重载是在同一作用域内的不同函数,而重写是发生在父子类之间的函数。
- 参数列表:重载要求参数列表不同,而重写的参数列表必须完全相同。
- 虚函数:重写通常与虚函数一起使用,以实现运行时多态。重载不涉及虚函数。
- 多态性:重载是编译时多态,而重写是运行时多态。
- 访问修饰符:在重写时,基类的函数通常被声明为
virtual
,而重载的函数没有这个要求。
结语
通过本课的学习,你了解了如何使用函数组织代码,包括函数的定义、调用、参数传递、返回值、递归、重载、数组传递、引用传递、内联函数和lambda函数。
函数是C++中非常重要的概念,它们使得代码更加模块化、易于理解和维护。掌握函数的使用对于编写高质量的C++程序至关重要。