C++ 函数及参数传递
概述
函数是C++程序的基本构建块,它将相关的代码组织在一起,实现特定的功能。函数提供了代码重用性、模块化和抽象化的能力。本章将详细介绍函数的定义、调用、参数传递方式以及相关的高级特性。
🔧 函数基础
函数定义和声明
cpp
#include <iostream>
// 函数声明(原型)
int add(int a, int b);
void greet(const std::string& name);
double calculateArea(double radius);
// 函数定义
int add(int a, int b) {
return a + b;
}
void greet(const std::string& name) {
std::cout << "Hello, " << name << "!" << std::endl;
}
double calculateArea(double radius) {
const double PI = 3.14159;
return PI * radius * radius;
}
int main() {
// 函数调用
int result = add(5, 3);
std::cout << "5 + 3 = " << result << std::endl;
greet("Alice");
double area = calculateArea(5.0);
std::cout << "半径5的圆面积: " << area << std::endl;
return 0;
}函数的组成部分
cpp
#include <iostream>
// 函数组成部分详解
/*
返回类型 函数名(参数列表) {
函数体
return 返回值; // 如果返回类型不是void
}
*/
// 1. 无参数函数
void sayHello() {
std::cout << "Hello, World!" << std::endl;
}
// 2. 有参数函数
int multiply(int x, int y) {
return x * y;
}
// 3. 默认参数
void printMessage(const std::string& msg, int times = 1) {
for (int i = 0; i < times; i++) {
std::cout << msg << std::endl;
}
}
// 4. 多个返回值(使用结构体)
struct Point {
double x, y;
};
Point createPoint(double x, double y) {
return {x, y}; // C++11 列表初始化
}
int main() {
sayHello();
int product = multiply(4, 7);
std::cout << "4 × 7 = " << product << std::endl;
printMessage("Default once");
printMessage("Repeat", 3);
Point p = createPoint(10.5, 20.3);
std::cout << "Point: (" << p.x << ", " << p.y << ")" << std::endl;
return 0;
}📦 参数传递方式
值传递(Pass by Value)
cpp
#include <iostream>
// 值传递:传递参数的副本
void modifyValue(int x) {
x = 100; // 只修改副本,不影响原变量
std::cout << "函数内 x = " << x << std::endl;
}
void expensiveCopy(std::vector<int> vec) {
// 整个vector被复制,开销大
vec.push_back(999);
std::cout << "函数内vector大小: " << vec.size() << std::endl;
}
int main() {
std::cout << "=== 值传递示例 ===" << std::endl;
int original = 42;
std::cout << "调用前 original = " << original << std::endl;
modifyValue(original);
std::cout << "调用后 original = " << original << std::endl; // 仍然是42
std::vector<int> numbers = {1, 2, 3};
std::cout << "调用前vector大小: " << numbers.size() << std::endl;
expensiveCopy(numbers);
std::cout << "调用后vector大小: " << numbers.size() << std::endl; // 仍然是3
return 0;
}引用传递(Pass by Reference)
cpp
#include <iostream>
#include <vector>
// 引用传递:传递变量的引用(别名)
void modifyByReference(int& x) {
x = 100; // 直接修改原变量
std::cout << "函数内 x = " << x << std::endl;
}
void efficientModify(std::vector<int>& vec) {
// 不复制vector,直接操作原对象
vec.push_back(999);
std::cout << "函数内vector大小: " << vec.size() << std::endl;
}
// const引用:只读访问,不复制
void readOnlyAccess(const std::vector<int>& vec) {
std::cout << "只读访问,vector大小: " << vec.size() << std::endl;
// vec.push_back(1); // 错误!不能修改const引用
}
// 交换两个变量
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
std::cout << "=== 引用传递示例 ===" << std::endl;
int original = 42;
std::cout << "调用前 original = " << original << std::endl;
modifyByReference(original);
std::cout << "调用后 original = " << original << std::endl; // 变成100
std::vector<int> numbers = {1, 2, 3};
std::cout << "调用前vector大小: " << numbers.size() << std::endl;
efficientModify(numbers);
std::cout << "调用后vector大小: " << numbers.size() << std::endl; // 变成4
readOnlyAccess(numbers);
// 交换示例
int x = 10, y = 20;
std::cout << "交换前: x = " << x << ", y = " << y << std::endl;
swap(x, y);
std::cout << "交换后: x = " << x << ", y = " << y << std::endl;
return 0;
}指针传递(Pass by Pointer)
cpp
#include <iostream>
// 指针传递:传递变量地址的副本
void modifyByPointer(int* x) {
if (x != nullptr) { // 安全检查
*x = 100; // 通过指针修改原变量
std::cout << "函数内 *x = " << *x << std::endl;
}
}
void allocateMemory(int** ptr, int size) {
*ptr = new int[size]; // 修改指针本身
for (int i = 0; i < size; i++) {
(*ptr)[i] = i + 1;
}
}
// 比较字符串长度
int compareStringLength(const char* str1, const char* str2) {
int len1 = strlen(str1);
int len2 = strlen(str2);
return len1 - len2;
}
int main() {
std::cout << "=== 指针传递示例 ===" << std::endl;
int original = 42;
std::cout << "调用前 original = " << original << std::endl;
modifyByPointer(&original); // 传递地址
std::cout << "调用后 original = " << original << std::endl;
// 空指针安全
modifyByPointer(nullptr); // 不会崩溃
// 动态内存分配
int* array = nullptr;
allocateMemory(&array, 5);
std::cout << "动态分配的数组: ";
for (int i = 0; i < 5; i++) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
delete[] array; // 释放内存
// 字符串比较
const char* str1 = "hello";
const char* str2 = "world";
int diff = compareStringLength(str1, str2);
std::cout << "字符串长度差: " << diff << std::endl;
return 0;
}🎯 函数重载
基本函数重载
cpp
#include <iostream>
#include <string>
// 函数重载:相同函数名,不同参数
class Calculator {
public:
// 整数加法
int add(int a, int b) {
std::cout << "整数加法: ";
return a + b;
}
// 浮点数加法
double add(double a, double b) {
std::cout << "浮点数加法: ";
return a + b;
}
// 三个参数的加法
int add(int a, int b, int c) {
std::cout << "三数加法: ";
return a + b + c;
}
// 字符串连接
std::string add(const std::string& a, const std::string& b) {
std::cout << "字符串连接: ";
return a + b;
}
};
// 全局函数重载
void print(int value) {
std::cout << "整数: " << value << std::endl;
}
void print(double value) {
std::cout << "浮点数: " << value << std::endl;
}
void print(const std::string& value) {
std::cout << "字符串: " << value << std::endl;
}
void print(const char* value) {
std::cout << "C字符串: " << value << std::endl;
}
int main() {
Calculator calc;
std::cout << calc.add(5, 3) << std::endl;
std::cout << calc.add(2.5, 3.7) << std::endl;
std::cout << calc.add(1, 2, 3) << std::endl;
std::cout << calc.add(std::string("Hello, "), std::string("World!")) << std::endl;
// 函数重载解析
print(42);
print(3.14);
print(std::string("C++ String"));
print("C String");
return 0;
}重载解析规则
cpp
#include <iostream>
// 重载解析优先级演示
void func(int x) {
std::cout << "func(int): " << x << std::endl;
}
void func(double x) {
std::cout << "func(double): " << x << std::endl;
}
void func(int x, int y) {
std::cout << "func(int, int): " << x << ", " << y << std::endl;
}
// const重载
void process(int& x) {
std::cout << "process(int&): " << x << std::endl;
x++;
}
void process(const int& x) {
std::cout << "process(const int&): " << x << std::endl;
}
int main() {
std::cout << "=== 重载解析示例 ===" << std::endl;
// 精确匹配
func(42); // 调用 func(int)
func(3.14); // 调用 func(double)
func(1, 2); // 调用 func(int, int)
// 类型转换
func(3.14f); // float->double, 调用 func(double)
// const重载
int mutable_var = 10;
const int const_var = 20;
process(mutable_var); // 调用 process(int&)
process(const_var); // 调用 process(const int&)
process(100); // 临时对象,调用 process(const int&)
return 0;
}📚 高级函数特性
默认参数
cpp
#include <iostream>
#include <string>
// 默认参数函数
void createUser(const std::string& name,
int age = 0,
const std::string& email = "unknown@example.com",
bool isActive = true) {
std::cout << "用户信息:" << std::endl;
std::cout << " 姓名: " << name << std::endl;
std::cout << " 年龄: " << age << std::endl;
std::cout << " 邮箱: " << email << std::endl;
std::cout << " 状态: " << (isActive ? "活跃" : "非活跃") << std::endl;
std::cout << std::endl;
}
// 默认参数规则
void configureSettings(int width = 800, int height = 600, bool fullscreen = false);
// 实现必须省略默认值
void configureSettings(int width, int height, bool fullscreen) {
std::cout << "设置: " << width << "x" << height
<< (fullscreen ? " (全屏)" : " (窗口)") << std::endl;
}
int main() {
std::cout << "=== 默认参数示例 ===" << std::endl;
// 不同的调用方式
createUser("Alice"); // 只传必需参数
createUser("Bob", 25); // 传递部分参数
createUser("Charlie", 30, "charlie@email.com"); // 传递更多参数
createUser("Diana", 28, "diana@email.com", false); // 传递所有参数
// 配置示例
configureSettings(); // 使用所有默认值
configureSettings(1024); // 只设置宽度
configureSettings(1920, 1080); // 设置宽度和高度
configureSettings(1920, 1080, true); // 设置所有参数
return 0;
}内联函数
cpp
#include <iostream>
// 内联函数:建议编译器在调用处展开
inline int max(int a, int b) {
return (a > b) ? a : b;
}
inline double square(double x) {
return x * x;
}
// 类内定义的函数自动成为内联函数
class MathUtils {
public:
// 自动内联
int add(int a, int b) {
return a + b;
}
// 显式内联
inline double multiply(double a, double b) {
return a * b;
}
};
// 复杂函数不适合内联
inline void complexFunction() {
// 包含循环、递归等复杂逻辑的函数
// 编译器可能忽略内联建议
for (int i = 0; i < 1000; i++) {
std::cout << "This is too complex for inlining" << std::endl;
}
}
int main() {
std::cout << "=== 内联函数示例 ===" << std::endl;
int result = max(10, 20);
std::cout << "max(10, 20) = " << result << std::endl;
double sq = square(5.5);
std::cout << "square(5.5) = " << sq << std::endl;
MathUtils utils;
std::cout << "add(3, 4) = " << utils.add(3, 4) << std::endl;
std::cout << "multiply(2.5, 4.0) = " << utils.multiply(2.5, 4.0) << std::endl;
return 0;
}函数指针和函数对象
cpp
#include <iostream>
#include <functional>
// 普通函数
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
// 函数对象(仿函数)
class Subtract {
public:
int operator()(int a, int b) const {
return a - b;
}
};
// 使用函数指针的高阶函数
int calculate(int x, int y, int (*operation)(int, int)) {
return operation(x, y);
}
// 使用std::function的高阶函数
int flexibleCalculate(int x, int y, const std::function<int(int, int)>& operation) {
return operation(x, y);
}
int main() {
std::cout << "=== 函数指针和函数对象 ===" << std::endl;
// 函数指针
int (*funcPtr)(int, int) = add;
std::cout << "函数指针调用: " << funcPtr(5, 3) << std::endl;
// 函数指针数组
int (*operations[])(int, int) = {add, multiply};
std::cout << "add(10, 5) = " << operations[0](10, 5) << std::endl;
std::cout << "multiply(10, 5) = " << operations[1](10, 5) << std::endl;
// 高阶函数
std::cout << "calculate with add: " << calculate(8, 3, add) << std::endl;
std::cout << "calculate with multiply: " << calculate(8, 3, multiply) << std::endl;
// 函数对象
Subtract sub;
std::cout << "函数对象: " << sub(10, 4) << std::endl;
// std::function
std::function<int(int, int)> func = add;
std::cout << "std::function: " << flexibleCalculate(7, 2, func) << std::endl;
func = multiply;
std::cout << "std::function: " << flexibleCalculate(7, 2, func) << std::endl;
func = sub;
std::cout << "std::function: " << flexibleCalculate(7, 2, func) << std::endl;
// Lambda表达式
auto lambda = [](int a, int b) { return a / b; };
std::cout << "Lambda: " << flexibleCalculate(15, 3, lambda) << std::endl;
return 0;
}🔄 递归函数
基本递归
cpp
#include <iostream>
// 阶乘计算
unsigned long long factorial(int n) {
// 基础情况
if (n <= 1) {
return 1;
}
// 递归调用
return n * factorial(n - 1);
}
// 斐波那契数列
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 优化的斐波那契(记忆化)
int fibonacciOptimized(int n, int memo[] = nullptr) {
static int staticMemo[100] = {0};
if (memo == nullptr) memo = staticMemo;
if (n <= 1) return n;
if (memo[n] != 0) return memo[n];
memo[n] = fibonacciOptimized(n - 1, memo) + fibonacciOptimized(n - 2, memo);
return memo[n];
}
// 二分查找(递归版本)
bool binarySearch(const int arr[], int left, int right, int target) {
if (left > right) {
return false; // 未找到
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return true; // 找到了
} else if (arr[mid] > target) {
return binarySearch(arr, left, mid - 1, target);
} else {
return binarySearch(arr, mid + 1, right, target);
}
}
int main() {
std::cout << "=== 递归函数示例 ===" << std::endl;
// 阶乘
for (int i = 0; i <= 10; i++) {
std::cout << i << "! = " << factorial(i) << std::endl;
}
// 斐波那契
std::cout << "\n斐波那契数列:" << std::endl;
for (int i = 0; i <= 10; i++) {
std::cout << "F(" << i << ") = " << fibonacci(i) << std::endl;
}
// 优化的斐波那契
std::cout << "\n优化的斐波那契:" << std::endl;
std::cout << "F(30) = " << fibonacciOptimized(30) << std::endl;
// 二分查找
int sortedArray[] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
int size = sizeof(sortedArray) / sizeof(sortedArray[0]);
int target = 7;
bool found = binarySearch(sortedArray, 0, size - 1, target);
std::cout << "\n查找 " << target << ": " << (found ? "找到" : "未找到") << std::endl;
target = 8;
found = binarySearch(sortedArray, 0, size - 1, target);
std::cout << "查找 " << target << ": " << (found ? "找到" : "未找到") << std::endl;
return 0;
}📋 函数最佳实践
函数设计原则
cpp
#include <iostream>
#include <vector>
#include <string>
// 1. 单一职责原则
bool isValidEmail(const std::string& email) {
// 简化的邮箱验证
return email.find('@') != std::string::npos &&
email.find('.') != std::string::npos;
}
void sendEmail(const std::string& to, const std::string& subject, const std::string& body) {
if (!isValidEmail(to)) {
std::cout << "无效的邮箱地址: " << to << std::endl;
return;
}
// 发送邮件的逻辑
std::cout << "发送邮件到: " << to << std::endl;
std::cout << "主题: " << subject << std::endl;
std::cout << "内容: " << body << std::endl;
}
// 2. 输入验证
double safeDivide(double numerator, double denominator) {
if (denominator == 0.0) {
std::cerr << "错误:除数不能为零" << std::endl;
return 0.0; // 或抛出异常
}
return numerator / denominator;
}
// 3. 使用const正确性
void printVector(const std::vector<int>& vec) { // const引用,不修改不复制
for (const int& value : vec) {
std::cout << value << " ";
}
std::cout << std::endl;
}
// 4. 明确的函数命名
bool isEmpty(const std::string& str) {
return str.empty();
}
int getLength(const std::string& str) {
return str.length();
}
void updateUserStatus(int userId, bool isActive) {
std::cout << "更新用户 " << userId << " 状态为: "
<< (isActive ? "活跃" : "非活跃") << std::endl;
}
int main() {
std::cout << "=== 函数设计最佳实践 ===" << std::endl;
// 使用验证函数
sendEmail("user@example.com", "测试", "这是一封测试邮件");
sendEmail("invalid-email", "测试", "这不会发送");
// 安全除法
std::cout << "10 / 2 = " << safeDivide(10.0, 2.0) << std::endl;
std::cout << "10 / 0 = " << safeDivide(10.0, 0.0) << std::endl;
// const正确性
std::vector<int> numbers = {1, 2, 3, 4, 5};
printVector(numbers);
// 明确的函数使用
std::string text = "Hello";
std::cout << "字符串是否为空: " << isEmpty(text) << std::endl;
std::cout << "字符串长度: " << getLength(text) << std::endl;
updateUserStatus(123, true);
return 0;
}总结
C++函数是构建程序的重要工具,提供了代码组织和重用的能力:
核心概念
- 函数定义:返回类型、函数名、参数列表、函数体
- 参数传递:值传递、引用传递、指针传递
- 函数重载:相同函数名,不同参数类型或数量
- 高级特性:默认参数、内联函数、递归、函数指针
最佳实践
- 使用const引用传递大对象避免复制
- 合理使用函数重载提高接口易用性
- 遵循单一职责原则设计函数
- 进行输入验证保证函数健壮性
- 使用清晰的函数命名表达意图
掌握函数的使用是C++编程的基础,良好的函数设计能显著提高代码的可读性、可维护性和重用性。