细究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 和其与函数指针之间的区别!

相关推荐
TeYiToKu8 分钟前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
互联网打工人no115 分钟前
每日一题——第一百二十四题
c语言
爱吃生蚝的于勒18 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~22 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
洋24042 分钟前
C语言常用标准库函数
c语言·开发语言
脉牛杂德1 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz1 小时前
STL--哈希
c++·算法·哈希算法
CSUC1 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++
Vanranrr1 小时前
C++ QT
java·c++·qt
徐嵌1 小时前
STM32项目---畜牧定位器
c语言·stm32·单片机·物联网·iot