细究C/C++函数指针

这里写目录标题

  • 函数指针
    • [1. 函数指针的声明](#1. 函数指针的声明)
    • [2. 指向函数的指针赋值](#2. 指向函数的指针赋值)
    • [3. 使用函数指针调用函数](#3. 使用函数指针调用函数)
    • [4. 将函数指针作为参数传递](#4. 将函数指针作为参数传递)
    • [5. 函数指针数组](#5. 函数指针数组)
  • std::function与函数指针
    • [1. `std::function` 的基本概念](#1. std::function 的基本概念)
    • [2. 与函数指针的对比](#2. 与函数指针的对比)
    • [3. `std::function` 的详细用法](#3. std::function 的详细用法)
      • [3.1. 使用普通函数](#3.1. 使用普通函数)
      • [3.2. 使用 Lambda 表达式](#3.2. 使用 Lambda 表达式)
      • [3.3. 使用 `std::bind` 绑定参数](#3.3. 使用 std::bind 绑定参数)
    • [4. 在容器中使用 `std::function`](#4. 在容器中使用 std::function)
    • [5. 性能考虑](#5. 性能考虑)
    • [6. 总结](#6. 总结)

函数指针

在 C++ 中,函数指针是指向函数的指针。函数指针允许您动态调用函数、传递函数作为参数,或者存储函数的地址。

1. 函数指针的声明

函数指针的声明需要指定函数的返回类型和参数类型。基本语法如下:

cpp 复制代码
返回类型 (*指针名)(参数类型1, 参数类型2, ...);

示例:

假设有一个返回 int 类型、接受两个 int 类型参数的函数指针:

cpp 复制代码
int (*funcPtr)(int, int);

2. 指向函数的指针赋值

可以将函数的地址赋值给函数指针。注意:在赋值时不需要使用取地址符 &,因为函数名本身就是一个指向函数的指针。

cpp 复制代码
int add(int a, int b) {
    return a + b;
}

int (*funcPtr)(int, int) = add;  // 将 add 的地址赋给 funcPtr

3. 使用函数指针调用函数

通过函数指针调用函数的语法如下:

cpp 复制代码
int result = (*funcPtr)(arg1, arg2);

或者,您也可以直接使用函数指针名:

cpp 复制代码
int result = funcPtr(arg1, arg2);

示例代码

cpp 复制代码
#include <iostream>

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

int subtract(int a, int b) {
    return a - b;
}

int main() {
    // 声明函数指针
    int (*funcPtr)(int, int);

    // 将指针指向 add 函数
    funcPtr = add;

    // 调用 add 函数
    std::cout << "Add: " << funcPtr(3, 5) << std::endl;  // 输出 8

    // 将指针指向 subtract 函数
    funcPtr = subtract;

    // 调用 subtract 函数
    std::cout << "Subtract: " << funcPtr(10, 4) << std::endl;  // 输出 6

    return 0;
}

4. 将函数指针作为参数传递

您可以将函数指针作为参数传递给另一个函数。以下是一个简单示例:

cpp 复制代码
#include <iostream>

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

// 接受函数指针作为参数的函数
void performOperation(int (*operation)(int, int), int x, int y) {
    std::cout << "Result: " << operation(x, y) << std::endl;
}

int main() {
    // 传递函数指针
    performOperation(add, 5, 7);  // 输出 Result: 12
    return 0;
}

5. 函数指针数组

您可以创建一个函数指针数组,用于存储多个函数的地址。例如:

cpp 复制代码
#include <iostream>

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

int subtract(int a, int b) {
    return a - b;
}

int multiply(int a, int b) {
    return a * b;
}

int main() {
    // 创建一个函数指针数组
    int (*operations[3])(int, int) = { add, subtract, multiply };

    int x = 6, y = 3;

    for (int i = 0; i < 3; ++i) {
        std::cout << "Result: " << operations[i](x, y) << std::endl;
    }

    return 0;
}

函数指针必须与函数的签名(返回类型和参数类型)完全匹配。

使用函数指针时,要确保所指向的函数在调用时是有效的,以避免运行时错误。

std::function与函数指针

1. std::function 的基本概念

std::function 是 C++11 引入的一个通用、类型安全的可调用对象封装器。它可以存储任何可以调用的目标,包括:

  • 普通函数
  • 函数指针
  • Lambda 表达式
  • 绑定的函数对象(使用 std::bind
  • 实现了 operator() 的对象(函数对象)

基本语法

cpp 复制代码
#include <functional>

std::function<返回类型(参数类型1, 参数类型2, ...)> func;

2. 与函数指针的对比

特性 函数指针 std::function
类型 只能指向特定类型的函数 可以存储多种类型的可调用对象
类型安全 类型不安全 类型安全
灵活性 只能指向函数 可以指向 Lambda、函数对象等
内存管理 需要手动管理 自动管理
可用于泛型 不易与模板结合 易于与模板结合

3. std::function 的详细用法

3.1. 使用普通函数

cpp 复制代码
#include <iostream>
#include <functional>

// 普通函数
int add(int a, int b) {
    return a + b;
}

int main() {
    // 创建 std::function 对象
    std::function<int(int, int)> func = add;

    // 调用函数
    std::cout << "Add: " << func(3, 5) << std::endl;  // 输出 8

    return 0;
}

3.2. 使用 Lambda 表达式

Lambda 表达式是 std::function 的一种常见用法:

cpp 复制代码
#include <iostream>
#include <functional>

int main() {
    // 使用 Lambda 表达式
    std::function<int(int, int)> func = [](int a, int b) { return a + b; };

    std::cout << "Add: " << func(3, 5) << std::endl;  // 输出 8

    return 0;
}

3.3. 使用 std::bind 绑定参数

std::bind 允许您创建一个新函数,其中一些参数已经绑定到特定值:

cpp 复制代码
#include <iostream>
#include <functional>

int multiply(int a, int b) {
    return a * b;
}

int main() {
    // 创建一个绑定函数,绑定第一个参数为 2
    auto boundFunc = std::bind(multiply, 2, std::placeholders::_1);

    // 将绑定函数赋值给 std::function
    std::function<int(int)> func = boundFunc;

    std::cout << "Multiply: " << func(5) << std::endl;  // 输出 10

    return 0;
}

4. 在容器中使用 std::function

std::function 可以与 STL 容器结合使用,例如在一个 vector 中存储多个可调用对象:

cpp 复制代码
#include <iostream>
#include <functional>
#include <vector>

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

int subtract(int a, int b) {
    return a - b;
}

int main() {
    // 创建一个 std::function 向量
    std::vector<std::function<int(int, int)>> operations;

    // 将不同的函数添加到向量中
    operations.push_back(add);
    operations.push_back(subtract);

    int x = 10, y = 5;

    // 迭代并调用每个操作
    for (const auto& operation : operations) {
        std::cout << "Result: " << operation(x, y) << std::endl;  // 输出 5 和 15
    }

    return 0;
}

5. 性能考虑

  • 开销std::function 封装了可调用对象,因此在某些情况下可能会比直接使用函数指针稍慢,特别是在频繁调用的性能敏感场景中。
  • 内存使用std::function 在内部需要动态分配内存来存储可调用对象,这可能会增加内存开销。

6. 总结

  • 使用场景 :如果您需要灵活性,想要能够存储多种类型的可调用对象,那么 std::function 是理想的选择。如果您只需要简单的函数调用并且对性能非常敏感,可以考虑使用函数指针。
  • 现代 C++ 的特性std::function 和 Lambda 表达式结合使用,能够让代码更加简洁和可读。它们使得函数式编程风格在 C++ 中变得更加自然。

希望这些详细的说明能帮助您更好地理解 std::function 和其与函数指针之间的区别!

相关推荐
安大小万28 分钟前
C++ 学习:深入理解 Linux 系统中的冯诺依曼架构
linux·开发语言·c++
T.Ree.36 分钟前
C语言_自定义类型(结构体,枚举,联合)
c语言·开发语言
田梓燊42 分钟前
图论 八字码
c++·算法·图论
Tanecious.1 小时前
C语言--数据在内存中的存储
c语言·开发语言·算法
去往火星2 小时前
opencv在图片上添加中文汉字(c++以及python)
开发语言·c++·python
Zfox_3 小时前
【Linux】进程间关系与守护进程
linux·运维·服务器·c++
MSTcheng.3 小时前
C语言操作符(上)
c语言·开发语言
Ritsu栗子3 小时前
代码随想录算法训练营day35
c++·算法
好一点,更好一点4 小时前
systemC示例
开发语言·c++·算法
卷卷的小趴菜学编程4 小时前
c++之List容器的模拟实现
服务器·c语言·开发语言·数据结构·c++·算法·list