跳转到内容

C++ 可调用对象

来自代码酷

C++可调用对象[编辑 | 编辑源代码]

可调用对象(Callable Object)是C++中一类特殊的对象,可以被像函数一样调用。它们是C++标准库(STL)中函数对象(Function Object)概念的基础,也是现代C++编程中函数式编程风格的核心组成部分。

简介[编辑 | 编辑源代码]

在C++中,可调用对象是指任何可以像函数一样被调用的实体。具体来说,当你在一个对象后面加上括号`()`并传入适当的参数时,就是在调用一个可调用对象。C++中有多种类型的可调用对象,包括:

1. 函数指针 2. 函数对象(仿函数) 3. Lambda表达式 4. 类的成员函数指针 5. 可被转换为函数指针的类对象

理解可调用对象对于使用STL算法、设计回调机制以及实现高阶函数等高级编程技术至关重要。

可调用对象的类型[编辑 | 编辑源代码]

1. 函数指针[编辑 | 编辑源代码]

函数指针是最基础的可调用对象类型,它直接指向一个函数。

#include <iostream>

// 普通函数
void greet(const std::string& name) {
    std::cout << "Hello, " << name << "!\n";
}

int main() {
    // 函数指针
    void (*funcPtr)(const std::string&) = &greet;
    
    // 调用函数指针
    funcPtr("Alice");  // 输出: Hello, Alice!
    
    return 0;
}

输出:

Hello, Alice!

2. 函数对象(仿函数)[编辑 | 编辑源代码]

函数对象是重载了函数调用运算符`operator()`的类对象。

#include <iostream>

// 函数对象类
struct Adder {
    int operator()(int a, int b) const {
        return a + b;
    }
};

int main() {
    Adder add;  // 创建函数对象
    std::cout << add(3, 4) << "\n";  // 输出: 7
    
    return 0;
}

输出:

7

3. Lambda表达式[编辑 | 编辑源代码]

Lambda表达式是C++11引入的匿名函数对象,语法简洁。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    
    // Lambda表达式作为可调用对象
    auto print = [](int n) { std::cout << n << " "; };
    
    // 使用STL算法
    std::for_each(numbers.begin(), numbers.end(), print);  // 输出: 1 2 3 4 5 
    
    return 0;
}

输出:

1 2 3 4 5 

4. 类的成员函数指针[编辑 | 编辑源代码]

成员函数指针可以指向类的成员函数,需要通过对象或指针来调用。

#include <iostream>

class MyClass {
public:
    void sayHello() { std::cout << "Hello from MyClass!\n"; }
};

int main() {
    MyClass obj;
    
    // 成员函数指针
    void (MyClass::*memFuncPtr)() = &MyClass::sayHello;
    
    // 调用成员函数指针
    (obj.*memFuncPtr)();  // 输出: Hello from MyClass!
    
    return 0;
}

输出:

Hello from MyClass!

可调用对象的统一处理[编辑 | 编辑源代码]

C++提供了`std::function`模板类来统一处理各种类型的可调用对象。

#include <iostream>
#include <functional>

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

struct Multiply {
    int operator()(int a, int b) const { return a * b; }
};

int main() {
    // 使用std::function包装不同类型的可调用对象
    std::function<int(int, int)> func;
    
    func = add;  // 函数指针
    std::cout << func(2, 3) << "\n";  // 输出: 5
    
    func = Multiply();  // 函数对象
    std::cout << func(2, 3) << "\n";  // 输出: 6
    
    func = [](int a, int b) { return a - b; };  // Lambda
    std::cout << func(5, 3) << "\n";  // 输出: 2
    
    return 0;
}

输出:

5
6
2

实际应用案例[编辑 | 编辑源代码]

案例1:STL算法中的可调用对象[编辑 | 编辑源代码]

可调用对象常用于STL算法中作为谓词或操作函数。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> nums = {5, 3, 8, 1, 4};
    
    // 使用Lambda表达式作为排序准则
    std::sort(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;  // 降序排序
    });
    
    for (int n : nums) {
        std::cout << n << " ";  // 输出: 8 5 4 3 1
    }
    
    return 0;
}

输出:

8 5 4 3 1

案例2:回调机制[编辑 | 编辑源代码]

可调用对象常用于实现回调机制。

#include <iostream>
#include <functional>

class Button {
    std::function<void()> onClick;
public:
    void setOnClick(std::function<void()> callback) {
        onClick = callback;
    }
    void click() {
        if (onClick) onClick();
    }
};

int main() {
    Button btn;
    btn.setOnClick([]() {
        std::cout << "Button clicked!\n";
    });
    
    btn.click();  // 输出: Button clicked!
    
    return 0;
}

输出:

Button clicked!

可调用对象关系图[编辑 | 编辑源代码]

graph TD A[可调用对象] --> B[函数指针] A --> C[函数对象] A --> D[Lambda表达式] A --> E[成员函数指针] A --> F[可转换为函数指针的类] C --> G[重载operator()] D --> H[捕获列表] D --> I[参数列表] D --> J[函数体]

数学表示[编辑 | 编辑源代码]

从数学角度看,可调用对象实现了函数的概念。给定输入集合X和输出集合Y,可调用对象f实现了映射:

f:XY

在C++中,这个映射关系通过不同的语法结构实现,但都遵循相同的调用模式。

总结[编辑 | 编辑源代码]

可调用对象是C++中强大的抽象工具,它允许开发者:

  • 以统一的方式处理不同类型的"函数"
  • 实现灵活的回调机制
  • 创建高阶函数
  • 编写更通用的模板代码

掌握可调用对象的概念和使用方法,是成为熟练C++程序员的重要一步。随着C++标准的演进,Lambda表达式等新特性使得可调用对象的使用变得更加方便和强大。