C++ 函数详解:从基础到高级应用

C++语言基础——函数(详解) 函数全名叫计算机函数,它可以帮助你完成一些特定的程序。你可以把它简单理解成一把手枪。 手枪的作用:完成几发子弹进行射击的功能 手枪的结构:有固定的几个部分构成 所以,手枪是具有一定格式,可以完成一些特定功能的一件工具,这就是函数 阅读详情

C++ 函数详解:从基础到高级应用

函数是 C++ 程序的基本构建块,是实现代码模块化、复用性和可读性的核心机制。本文将全面讲解 C++ 函数的方方面面,从基本定义到高级特性,帮助你深入理解并灵活运用函数。

一、函数的基本概念与结构

1.1 什么是函数

函数是一个完成特定任务的代码块,它接收输入(参数),执行一系列操作,并可能返回一个结果。在 C++ 中,函数可以分为:

  • 标准库函数:如printf()、sqrt()等
  • 自定义函数:由开发者根据需求定义

1.2 函数的基本结构

C++ 函数的基本结构如下:

cpp

运行

返回类型 函数名(参数列表) {
    // 函数体:执行操作的语句
    return 返回值; // 若返回类型为void则不需要
}
  • 返回类型:函数执行完毕后返回值的类型,可以是基本类型、自定义类型,或void(表示无返回值)
  • 函数名:遵循标识符命名规则,应体现函数功能
  • 参数列表:函数接收的输入,由类型和变量名组成,多个参数用逗号分隔
  • 函数体:包含实现函数功能的语句块
  • 返回语句:将结果返回给调用者,void类型函数可以省略

1.3 函数声明与定义

函数需要先声明后使用,声明告诉编译器函数的存在和接口,定义则提供函数的实现。

cpp

运行

// 函数声明(原型)
int add(int a, int b); // 只需指定参数类型和返回类型,参数名可省略

// 函数定义
int add(int a, int b) {
    return a + b;
}

函数声明通常放在头文件(.h)中,定义放在源文件(.cpp)中,这样可以实现代码的分离编译。

二、函数参数与返回值

2.1 参数传递方式

C++ 有三种主要的参数传递方式:

  1. 值传递:将实参的值复制给形参,函数内部对形参的修改不影响实参

cpp

运行

void increment(int x) {
    x++; // 只修改形参,不影响实参
}

int main() {
    int num = 5;
    increment(num);
    cout << num << endl; // 输出5,实参未改变
    return 0;
}
  1. 指针传递:传递实参的地址,函数内部通过指针可以修改实参的值

cpp

运行

void increment(int* x) {
    (*x)++; // 通过指针修改实参
}

int main() {
    int num = 5;
    increment(&num);
    cout << num << endl; // 输出6,实参被修改
    return 0;
}
  1. 引用传递:传递实参的别名,函数内部对引用的修改直接影响实参

cpp

运行

void increment(int& x) {
    x++; // 通过引用修改实参
}

int main() {
    int num = 5;
    increment(num);
    cout << num << endl; // 输出6,实参被修改
    return 0;
}

引用传递相比指针传递更简洁安全,是 C++ 中推荐的方式。

2.2 默认参数

函数可以指定默认参数值,当调用函数时未提供对应实参,将使用默认值:

cpp

运行

// 默认参数必须从右向左定义
int power(int base, int exp = 2) {
    int result = 1;
    for (int i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

int main() {
    cout << power(3) << endl;   // 使用默认参数,计算3^2=9
    cout << power(3, 3) << endl; // 提供实参,计算3^3=27
    return 0;
}

注意:

  • 默认参数只能在函数声明中指定一次
  • 默认参数必须从右向左依次定义,不能跳过某个参数指定后面的默认值

2.3 函数返回值

函数的返回值可以是任意类型,包括基本类型、指针、引用和自定义类型:

cpp

运行

// 返回基本类型
int getSum(int a, int b) {
    return a + b;
}

// 返回指针
int* createArray(int size) {
    return new int[size]; // 返回动态分配数组的指针
}

// 返回引用
int& getElement(int arr[], int index) {
    return arr[index]; // 返回数组元素的引用
}

注意:

  • 不要返回局部变量的指针或引用,因为函数结束后局部变量会被销毁
  • 返回引用可以作为左值使用:getElement(arr, 0) = 10;

三、函数重载

函数重载是 C++ 的多态特性之一,允许在同一作用域内定义多个同名函数,只要它们的参数列表(参数类型、数量或顺序)不同。

3.1 重载的基本形式

cpp

运行

// 重载函数:参数数量不同
int add(int a, int b) {
    return a + b;
}

int add(int a, int b, int c) {
    return a + b + c;
}

// 重载函数:参数类型不同
double add(double a, double b) {
    return a + b;
}

// 重载函数:参数顺序不同
void print(int a, double b) {
    cout << "int: " << a << ", double: " << b << endl;
}

void print(double a, int b) {
    cout << "double: " << a << ", int: " << b << endl;
}

3.2 重载决议

编译器通过分析实参的类型、数量和顺序来确定调用哪个重载函数,这个过程称为重载决议。

cpp

运行

int main() {
    add(2, 3);         // 调用add(int, int)
    add(2, 3, 4);      // 调用add(int, int, int)
    add(2.5, 3.5);     // 调用add(double, double)
    print(5, 3.14);    // 调用print(int, double)
    print(3.14, 5);    // 调用print(double, int)
    return 0;
}

3.3 重载的注意事项

  1. 返回类型不同不能作为重载的依据:

cpp

运行

// 错误:仅返回类型不同不能重载
int add(int a, int b) { return a + b; }
double add(int a, int b) { return (double)(a + b); }
  1. 默认参数可能导致重载二义性:

cpp

运行

// 潜在问题:调用show()时会有歧义
void show(int a = 0) { cout << a << endl; }
void show() { cout << "Default" << endl; }

四、内联函数

内联函数(inline function)是一种特殊的函数,编译器会尝试在调用处展开函数体,而不是进行常规的函数调用,从而减少函数调用的开销。

4.1 内联函数的定义

使用inline关键字声明内联函数:

cpp

运行

inline int max(int a, int b) {
    return (a > b) ? a : b;
}

4.2 内联函数的特性

  1. 减少调用开销:适合小型函数,避免函数调用的栈操作、跳转等开销
  2. 代码膨胀:内联会增加代码体积,大型函数不适合内联
  3. 建议性质:inline只是对编译器的建议,编译器可能会忽略
  4. 通常在头文件中实现:因为内联函数需要在调用处展开,需要可见其实现

4.3 内联函数与宏的区别

内联函数类似于 C 语言的宏,但更安全:

cpp

运行

// 宏定义(不安全)
#define MAX(a, b) ((a) > (b) ? (a) : (b))

// 内联函数(安全)
inline int max(int a, int b) {
    return (a > b) ? a : b;
}

区别:

  • 内联函数会进行类型检查,宏不会
  • 内联函数可以调试,宏不能
  • 宏可能有副作用(如MAX(a++, b++)),内联函数不会

五、递归函数

递归函数是指在函数体内调用自身的函数,适用于解决可以分解为相似子问题的问题(如阶乘、斐波那契数列、树遍历等)。

5.1 递归的基本结构

递归函数通常包含两个部分:

  1. 基准情况:不需要递归就能解决的简单情况
  2. 递归步骤:将问题分解为更小的子问题,并调用自身解决

cpp

运行

// 计算n的阶乘:n! = n × (n-1) × ... × 1
int factorial(int n) {
    // 基准情况
    if (n == 0 || n == 1) {
        return 1;
    }
    // 递归步骤
    return n * factorial(n - 1);
}

5.2 递归的优缺点

优点:

  • 代码简洁,符合问题的自然描述
  • 适合解决递归结构的问题(如树、图)

缺点:

  • 可能导致栈溢出(递归深度过大时)
  • 可能存在重复计算(可通过记忆化优化)

5.3 递归与迭代的转换

许多递归问题可以转换为迭代(循环)形式,避免栈溢出风险:

cpp

运行

// 迭代版本的阶乘计算
int factorialIterative(int n) {
    int result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
}

六、函数指针

函数指针是指向函数的指针变量,可以像其他指针一样使用,支持函数的间接调用,是 C++ 中实现回调函数的基础。

6.1 函数指针的定义与使用

cpp

运行

// 定义函数
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }

// 定义函数指针类型
typedef int (*ArithmeticFunc)(int, int);

int main() {
    // 声明并初始化函数指针
    ArithmeticFunc func = add;
    
    // 使用函数指针调用函数
    cout << func(5, 3) << endl; // 调用add(5,3),输出8
    
    // 改变函数指针指向
    func = subtract;
    cout << func(5, 3) << endl; // 调用subtract(5,3),输出2
    
    return 0;
}

6.2 函数指针作为参数(回调函数)

函数指针常用作其他函数的参数,实现回调机制:

cpp

运行

// 回调函数:比较两个整数
bool ascending(int a, int b) { return a < b; }
bool descending(int a, int b) { return a > b; }

// 排序函数,接受回调函数指定排序方式
void sort(int arr[], int size, bool (*compare)(int, int)) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (!compare(arr[j], arr[j + 1])) {
                // 交换元素
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

int main() {
    int numbers[] = {5, 2, 8, 1, 9};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    
    // 按升序排序
    sort(numbers, size, ascending);
    
    // 按降序排序
    sort(numbers, size, descending);
    
    return 0;
}

七、C++11 及以上的函数新特性

7.1 lambda 表达式

C++11 引入了 lambda 表达式,允许在需要函数的地方直接定义匿名函数:

cpp

运行

#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {5, 2, 8, 1, 9};
    
    // 使用lambda表达式作为排序的比较函数
    std::sort(numbers.begin(), numbers.end(), 
              [](int a, int b) { return a < b; }); // 升序排序
    
    // 使用lambda表达式遍历容器
    for_each(numbers.begin(), numbers.end(),
             [](int n) { cout << n << " "; });
    
    return 0;
}

lambda 表达式的基本形式:[捕获列表](参数列表) -> 返回类型 { 函数体 }

7.2 右值引用与移动语义

C++11 引入了右值引用(&&),允许函数高效地转移资源而不是复制:

cpp

运行

// 移动构造函数
class MyString {
private:
    char* data;
    int length;

public:
    // 移动构造函数
    MyString(MyString&& other) noexcept 
        : data(other.data), length(other.length) {
        // 转移资源所有权
        other.data = nullptr;
        other.length = 0;
    }
    
    // 移动赋值运算符
    MyString& operator=(MyString&& other) noexcept {
        if (this != &other) {
            delete[] data;
            // 转移资源所有权
            data = other.data;
            length = other.length;
            other.data = nullptr;
            other.length = 0;
        }
        return *this;
    }
};

7.3 constexpr 函数

C++11 引入constexpr函数,允许在编译期计算结果:

cpp

运行

// constexpr函数:可以在编译期计算
constexpr int factorial(int n) {
    return (n <= 1) ? 1 : (n * factorial(n - 1));
}

int main() {
    constexpr int result = factorial(5); // 编译期计算,结果为120
    int arr[factorial(3)]; // 合法,编译期已知大小为6
    return 0;
}

C++14 放松了对constexpr函数的限制,允许包含更多类型的语句。

八、函数设计最佳实践

  1. 单一职责原则:一个函数应只做一件事,保持函数简短精悍
  2. 函数命名:使用有意义的名称,清晰表达函数功能
  3. 参数数量:尽量减少参数数量,过多参数可考虑封装为结构体
  4. 避免副作用:函数应尽量只通过返回值与外部交互,减少对全局变量的修改
  5. 错误处理:明确函数可能的错误情况,并提供清晰的错误处理机制
  6. 文档注释:为函数添加注释,说明功能、参数含义、返回值和使用注意事项

cpp

运行

/**
 * 计算两个整数的最大公约数
 * @param a 第一个整数(必须为正)
 * @param b 第二个整数(必须为正)
 * @return 两个数的最大公约数
 * @throws std::invalid_argument 如果输入为非正数
 */
int gcd(int a, int b) {
    if (a <= 0 || b <= 0) {
        throw std::invalid_argument("输入必须为正数");
    }
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

九、总结

函数是 C++ 程序的核心组成部分,本文涵盖了函数的基本概念、参数传递、重载、内联函数、递归、函数指针以及 C++11 以来的新特性。掌握这些知识将帮助你编写更加模块化、高效和易维护的代码。

在实际开发中,应根据具体需求选择合适的函数特性,遵循函数设计的最佳实践,平衡代码的可读性、性能和可维护性。随着 C++ 标准的不断发展,函数相关的特性也在持续丰富,开发者需要不断学习以充分利用语言的新能力。

C++常用的一些函数及用法 1、memset()清空数组 memset(a,0,sizeof(a)),在string.h中定义。 2、memcpy()拷贝函数 memcpy(b,a,sizeof(int)*k) 从数组a复制k个元素到数组b。 memcpy(b,a,sizeof(a)) 把a数组复制到数组b中。 3、 sprintf(buf,"%d%d%d",a,b,c); char buf[maxn] ; int a = 5,b = 189,c = 384959; // 把信息输入到字符串中去, //用法和prin 阅读详情

相关推荐

C++函数详解:从基础到高级应用

在C++编程中,函数是构建程序的基本模块,是代码组织和重用的核心机制。无论是简单的脚本还是复杂的系统,合理使用函数都能显著提高代码质量。本文将全面介绍C++函数的各个方面,包括基本语法、参数传递、高级特性以及最佳实践。

vvilkin的学习备忘 1200

c++函数大全

函数是 C/C++语言中的一种程序组件单位。一个函数通常代表了一种数据处理的功能,由函数体和函数原型两部分组成。函数原型为这个数据处理功能指定一个标识符号(函数的名称)、说明被处理数据的组成及其类型、处理结果的类型。函数体由一组语句组成,具体实现数据处理的功能。这称为函数的定义。在某段程序中,一个函数可以被当作一个表达式来运行,称为函数的调用。函数的定义并不执行函数体中的语句,只是声明该函数包含这些语句、以及这些语句的运行顺序。函数在被调用之前,必须说明它的原型。被函数处理的数据一般作为函数的参数,在函数调

你猜我是谁? 9104

C++构造函数详解:从基础到高级应用

构造函数是面向对象编程中的核心概念,作为类对象的初始化机制,它在C++中具有多种特性和优化技巧。从原理上看,构造函数通过自动调用机制确保对象创建时的有效状态,支持重载、初始化列表等特性。在工程实践中,合理使用默认构造函数、参数化构造函数以及C++11引入的移动构造函数,能显著提升代码效率和安全性。现代C++开发中,构造函数的优化技巧如constexpr编译期构造、noexcept移动操作等,为高性能编程提供了更多可能。这些特性在内存管理、资源分配等场景下尤为重要,特别是在实现RAII模式时,构造函数的正确设

weixin_42548888的博客 268

C++中的各类函数详解

C++中的函数主要分为以下几类:内置函数、标准库函数、用户自定义函数、成员函数、虚函数和函数模板。下面分别介绍这些函数的特点和用法。

qxt1508520947的博客 1万+

C++函数完全指南:从基础到高级应用

本文全面介绍C++函数的基本概念和使用方法。主要内容包括:1) 函数的基本结构,包含返回类型、函数名、参数列表和函数体;2) 函数的定义与声明方式,强调函数原型的重要性;3) 参数传递的四种方式(值传递、指针传递、引用传递和常量引用传递)及其特点和适用场景;4) 函数的多种返回值类型(基本数据类型、指针和引用),特别指出返回引用时的注意事项。文章通过丰富代码示例,帮助读者系统掌握C++函数的正确使用技巧,提高代码的模块化、复用性和可维护性。

2202_75382767的博客 1626

深度学习|卷积神经网络

介绍卷积神经网络基本理论,包括卷积层、池化层和全连接层,并阐述LeNet卷积神经网络的构建过程。

weixin_58243219的博客 5722

C++函数总结,看这一篇就够了

C++函数总结

Jasmine-Lily的博客 6970

YOLOv8实战火焰和烟雾检测 (视频教程)

本课程将手把手地教大家使用YOLOv8结合可变形卷积(deformable convolution)训练火焰和烟雾数据集,完成一个多目标检测实战项目,可实时检测图像、视频、摄像头和流媒体(http/rtsp)中火焰和烟雾,并提供可视化演示界面 。

bai666ai的博客 1914

C++纯虚函数详解:从基础概念到高级应用

在面向对象编程中,虚函数是实现运行时多态的核心机制,而纯虚函数则是定义接口规范的关键技术。通过virtual关键字和=0语法,纯虚函数强制派生类必须实现特定功能,这种设计模式在大型项目中特别适合定义标准接口。从实现原理来看,纯虚函数通过虚函数表(vtable)实现动态绑定,虽然会带来一定的运行时开销,但提供了极高的扩展灵活性。在实际工程中,纯虚函数广泛应用于模板方法模式、观察者模式等设计模式实现,同时也是构建插件架构的基础。现代C++进一步通过override/final关键字和constexpr虚函数等特

weixin_30536861的博客 272

python sci sci-hub 爬论文

sci-hub 爬虫 后续加入对于时间的排序,下载最新文献 参考: https://www.guanjihuan.com/archives/6846 https://blog.youkuaiyun.com/czh2637750821/article/details/115508922

weixin_42783619的博客 3542

SRAM compiler选项中 Soft Error Repair (SER)

引起的瞬时故障,可能会影响 SRAM 中存储的数据。SER 功能通过某种机制检测并修复这些错误,从而提高存储器的可靠性。在 SRAM 编译器中,

hzmscut的博客 1154

C/C++主函数详解:从基础到高级应用

主函数(main function)是C/C++程序的执行入口点,作为程序与操作系统交互的桥梁,其设计直接影响程序的启动流程和命令行处理能力。从编译器原理角度看,main函数被标记为程序起始地址,保证了执行流程的可控性。标准形式包括无参、带命令行参数及环境变量访问三种模式,分别适用于不同场景。在工程实践中,主函数设计涉及错误处理、多平台兼容性、性能优化等关键技术,特别是在命令行工具开发和嵌入式系统中尤为重要。通过分离业务逻辑与入口代码,可以提升代码的可测试性和维护性。现代C++对main函数有严格约束,开发

weixin_29294395的博客 253

避开这些坑!用Python ReportLab生成PDF时字体处理与中文排版的5个关键技巧

本文针对Python ReportLab库在PDF自动化生成中常见的中文排版难题,提供了五个关键技巧。内容涵盖字体注册的稳健策略、段落样式的精细控制、表格内中文的换行对齐、页面布局管理以及性能优化,旨在帮助开发者彻底解决中文乱码、排版错位等问题,生成专业美观的PDF文档。

weixin_29250403的博客 624

C++构造函数与析构函数详解:从基础到高级应用

在面向对象编程中,构造函数和析构函数是类设计的核心组件,负责对象的初始化和资源释放。构造函数支持重载机制,允许通过不同参数列表创建对象,体现了C++的多态特性。析构函数则确保对象生命周期结束时资源被正确清理,防止内存泄漏。现代C++引入了委托构造函数、移动语义等特性,进一步优化了对象构造过程。理解这些机制对于开发高性能、健壮的C++程序至关重要,特别是在资源管理、RAII模式实现等场景中。本文深入解析构造函数重载规则、析构函数调用时机等关键技术点,帮助开发者掌握面向对象编程的核心实践。

weixin_30768881的博客 273

基于eBPF和LSM的强制文件访问控制系统架构设计和实现

本文介绍了一种基于 eBPF 与 Linux 安全模块(LSM)实现的强制文件访问控制系统。该系统利用 eBPF 的高性能和动态加载能力以及 LSM 的系统调用拦截功能,提供了灵活且强大的文件访问控制策略。文章详细描述了系统的设计思路、架构组成、关键代码实现及错误处理方式。通过用户空间程序与内核态 eBPF 程序的协作,实现了对文件操作的实时监控和控制,支持动态更新安全策略而无需重启系统。此外,文中还讨论了未来可能的扩展方向,如增加更多 hook 点、集成其他安全模块以及性能优化等。

Linux内核研究者 1839

第154章 点云大规模并行处理(GPU加速)

优化点云处理✨ 使用。

yumeiguo的博客 374

C/C++函数指针详解:从基础到高级应用

函数指针是C/C++编程中的核心概念,它存储函数的地址,允许通过指针间接调用函数。从原理上看,函数指针实现了代码的动态绑定,为程序提供了运行时灵活性。这种机制在回调函数、插件系统等场景中展现出重要技术价值,特别是在需要实现策略模式或事件处理时。通过函数指针数组和typedef等技巧,可以构建出模块化且易于扩展的代码结构。现代C++中的std::function和lambda表达式进一步扩展了这一概念,同时提供了更好的类型安全性。理解函数指针的工作原理对于掌握Linux系统编程、设计模式实现等关键技术至关重要

weixin_34199764的博客 296

嵌入式RTOS实战:uC/OS-III最新版移植指南(附项目源码)

本文提供uC/OS-III实时操作系统的完整移植指南,涵盖源码配置、工程搭建到任务调度的全流程。针对移植中的常见编译错误,给出关键修改方案(如中断重定义、配置使能等),附已验证的工程源码,通过LED任务实验验证稳定性,帮助开发者高效完成移植。适合嵌入式工程师及RTOS学习者参考。

Bit_Dong的博客 2472

promise-cpp高级特性详解:all/race/doWhile函数的实战应用

promise-cpp是一个采用Javascript风格设计的C++ promise/A+库,它为C++开发者提供了强大的异步编程能力。本文将深入探讨promise-cpp中的三个高级特性:all、race和doWhile函数,并通过实战案例展示它们的具体应用方法,帮助开发者更好地掌握异步编程技巧。 ## 一、并行任务管理:promise_all函数的使用场景 在异步编程中,我们经常需要同时执

gitblog_00499的博客 1074

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

C++虚函数全面解析:从原理到高级应用

虚函数是C++实现运行时多态的核心机制,通过virtualpublic:virtual void show() { // 虚函数声明virtual ~Base() {} // 虚析构函数编写更高效的代码避免常见陷阱设计更灵活的架构更好地进行调试和优化多态基类声明虚析构函数使用override明确覆盖关系避免在构造/析构中调用虚函数对性能关键代码考虑替代方案。

ikhsvjd的博客 2335

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C++链表详解:从基础概念到高级应用

链表是计算机科学中最基础也是最重要的数据结构之一,它在内存管理、算法实现和实际应用中扮演着关键角色。本文将详细介绍链表的概念、类型、C++实现以及实际应用场景,帮助读者全面理解这一重要的数据结构。

专注于人工智能领域的小何尚 1297

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: MFC List 控件详解:高效数据展示与管理
下一篇: C++后台进程
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值