C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ 包装器

C++中包装器的使用示例

作者:上去我就QWER

C++中的包装器是一种结构型设计模式,用于包装已有对象以转换接口或增强功能,下面就来详细的介绍一下如何使用,具有一定的参考价值,感兴趣的可以了解一下

在 C++ 中,包装器(Wrapper) 也常被称为适配器(Adapter),是一种设计模式(结构型模式)的实现——核心作用是包装一个已有对象(或函数、指针等),转换其接口、隐藏实现细节,或增强其功能,让原本不兼容的接口能够协同工作,同时不改变原对象的逻辑。

包装器的核心价值:解耦、复用、接口统一。它就像一个“翻译官”,让两个原本无法直接沟通的组件(如不同接口的类、不同格式的函数)能够正常交互。

一、C++ 中常见的包装器类型

C++ 标准库提供了多种内置包装器,同时也支持自定义包装器。按包装对象的不同,主要分为以下几类:

1. 函数包装器(std::function)

最常用的包装器,用于包装任意可调用对象(函数指针、lambda 表达式、函数对象、类成员函数等),统一其调用接口。

核心用途:

语法与示例:

#include <functional>
#include <iostream>

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

// 函数对象(仿函数)
struct Multiply {
    int operator()(int a, int b) { return a * b; }
};

// 类成员函数
class Calculator {
public:
    int subtract(int a, int b) { return a - b; }
};

int main() {
    // 包装普通函数
    std::function<int(int, int)> func1 = add;
    std::cout << func1(2, 3) << std::endl;  // 输出 5

    // 包装函数对象
    std::function<int(int, int)> func2 = Multiply{};
    std::cout << func2(2, 3) << std::endl;  // 输出 6

    // 包装 lambda 表达式
    std::function<int(int, int)> func3 = [](int a, int b) { return a / b; };
    std::cout << func3(6, 2) << std::endl;  // 输出 3

    // 包装类成员函数(需绑定实例)
    Calculator calc;
    std::function<int(int, int)> func4 = std::bind(&Calculator::subtract, &calc, std::placeholders::_1, std::placeholders::_2);
    std::cout << func4(5, 2) << std::endl;  // 输出 3

    return 0;
}

关键说明:

2. 指针包装器(智能指针:std::unique_ptr/std::shared_ptr)

智能指针是裸指针的包装器,核心作用是自动管理内存(避免内存泄漏),同时提供与裸指针兼容的接口(如 operator*operator->)。

核心用途:

示例:

#include <memory>
#include <iostream>

class MyClass {
public:
    MyClass() { std::cout << "MyClass 构造" << std::endl; }
    ~MyClass() { std::cout << "MyClass 析构" << std::endl; }
    void show() { std::cout << "Hello MyClass" << std::endl; }
};

int main() {
    // std::unique_ptr:独占所有权
    std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
    ptr1->show();  // 接口与裸指针一致

    // std::shared_ptr:共享所有权(引用计数)
    std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>();
    std::shared_ptr<MyClass> ptr3 = ptr2;  // 引用计数+1
    ptr3->show();

    // 无需手动 delete,作用域结束时自动析构
    return 0;
}

关键说明:

3. 迭代器适配器(std::reverse_iterator/std::insert_iterator等)

迭代器适配器是原生迭代器的包装器,用于转换迭代器的行为(如反向遍历、插入元素而非覆盖),让同一容器支持不同的遍历/操作方式。

常见类型:

示例(反向迭代器):

#include <vector>
#include <iostream>
#include <iterator>  // 包含迭代器适配器

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 正向遍历
    std::cout << "正向遍历:";
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";  // 输出 1 2 3 4 5
    }
    std::cout << std::endl;

    // 反向遍历(使用 reverse_iterator 包装 begin()/end())
    std::cout << "反向遍历:";
    for (auto it = std::reverse_iterator(vec.end()); it != std::reverse_iterator(vec.begin()); ++it) {
        std::cout << *it << " ";  // 输出 5 4 3 2 1
    }
    std::cout << std::endl;

    return 0;
}

关键说明:

4. 函数适配器(std::bind/std::not_fn)

函数适配器用于包装可调用对象,修改其参数列表或逻辑(如绑定参数、取反逻辑),生成新的可调用对象。

(1)std::bind:参数绑定适配器

核心作用:绑定可调用对象的部分参数,生成参数更少的新函数。

示例:

#include <functional>
#include <iostream>

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

int main() {
    // 绑定第一个参数为 10,生成新函数:int(int, int)
    auto add10 = std::bind(add, 10, std::placeholders::_1, std::placeholders::_2);
    std::cout << add10(2, 3) << std::endl;  // 10+2+3=15

    // 绑定后两个参数为 5、6,生成新函数:int(int)
    auto add56 = std::bind(add, std::placeholders::_1, 5, 6);
    std::cout << add56(4) << std::endl;  // 4+5+6=15

    return 0;
}

(2)std::not_fn:逻辑取反适配器

核心作用:包装返回布尔值的可调用对象,生成“逻辑取反”的新函数(C++17 引入)。

示例:

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

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 查找偶数(原逻辑:x % 2 == 0)
    auto even = [](int x) { return x % 2 == 0; };
    auto it1 = std::find_if(vec.begin(), vec.end(), even);
    std::cout << "第一个偶数:" << *it1 << std::endl;  // 输出 2

    // 查找奇数(包装 even,逻辑取反)
    auto odd = std::not_fn(even);
    auto it2 = std::find_if(vec.begin(), vec.end(), odd);
    std::cout << "第一个奇数:" << *it2 << std::endl;  // 输出 1

    return 0;
}

5. 自定义包装器(类适配器)

除了标准库提供的包装器,也可以手动实现类级别的包装器,用于适配不同接口的类。

场景:

假设已有一个旧接口的类 OldInterface,新代码需要使用统一的 NewInterface 接口,此时可通过包装器适配。

示例:

#include <iostream>
#include <string>

// 旧接口(无法修改)
class OldInterface {
public:
    void do_old_task(const std::string& msg) {
        std::cout << "旧接口执行任务:" << msg << std::endl;
    }
};

// 新接口(统一规范)
class NewInterface {
public:
    virtual ~NewInterface() = default;
    virtual void execute(const std::string& task) = 0;
};

// 包装器(适配器):将 OldInterface 适配为 NewInterface
class OldToNewAdapter : public NewInterface {
private:
    OldInterface old_obj;  // 包装旧接口对象
public:
    void execute(const std::string& task) override {
        // 转换接口:新接口的 execute 调用旧接口的 do_old_task
        old_obj.do_old_task("适配后:" + task);
    }
};

// 新代码使用统一接口
void use_new_interface(NewInterface& obj) {
    obj.execute("完成数据处理");
}

int main() {
    OldToNewAdapter adapter;
    use_new_interface(adapter);  // 输出:旧接口执行任务:适配后:完成数据处理
    return 0;
}

关键说明:

二、包装器的核心特性

  1. 接口转换:将被包装对象的接口转换为目标接口(如 OldInterfaceNewInterface);
  2. 透明性:用户无需关心被包装对象的细节,仅需使用包装器提供的统一接口;
  3. 增强功能:可在包装器中添加额外逻辑(如日志、缓存、权限校验),不修改原对象;
  4. 复用性:同一包装器可适配多个同类被包装对象(如 std::function 可包装任意符合签名的可调用对象)。

三、包装器与装饰器的区别(易混淆点)

很多人会将包装器(适配器)与装饰器(Decorator)混淆,两者核心差异在于目的不同

示例区别:

总结

C++ 中的包装器(适配器)是“接口转换与复用”的核心工具,分为:

其核心价值是解耦(隔离不同接口的组件)、复用(无需修改原有代码)、统一接口(降低使用成本),是 C++ 中实现灵活设计的重要手段。

到此这篇关于C++中包装器的使用示例的文章就介绍到这了,更多相关C++ 包装器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文