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

相关推荐
唐诺4 小时前
几种广泛使用的 C++ 编译器
c++·编译器
XH华5 小时前
初识C语言之二维数组(下)
c语言·算法
冷眼看人间恩怨5 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客6 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin6 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos7 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室8 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0018 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我588 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
Uu_05kkq8 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法