C++项目:仿muduo库高并发服务器--------Any类的实现


文章目录


前言

本篇文章是博主在学习仿muduo库高并发服务器项目所用到的功能模块,旨在设计一个可以存储任意类型的Any类。


一、服务器连接管理与通用协议上下文设计

在服务器的连接管理中,每个Connection对象负责一条客户端连接的管理 ,其必然涉及应用层协议的处理(如请求解析等)。因此,Connection内部必须设置协议处理上下文 ------用于记录协议解析进度、暂存中间数据 (如:解析协议得到的数据),从而控制协议处理的节奏 (例如应对网络通信中常见的粘包、半包 问题)。
我们得到的数据包可能不是一个完整的请求,但是我们依然需要对数据包解析,这时就可以将本次解析得到的信息存储起来,直到得到一个完整的请求

本项目需要满足不同应用层协议 (如 HTTP、TCP 私有协议 等),若让协议上下文与特定协议强绑定,会大幅提升代码耦合度 :后续新增或修改协议时,需频繁调整Connection的逻辑。为解决这一问题,协议的接收与解析上下文必须具有通用性 ,能够适配任意协议的上下文信息存储需求,这就需要一种可容纳不同数据结构的 "通用类型" 来承载

从技术实现来看,不同语言 / 标准库提供了不同的通用类型解决方案:

  • 在 C 语言中,通常通过void*(无类型指针) 实现通用数据管理,但这种方法不仅操作繁琐,还容易因类型不匹配引发安全问题
  • 在 C++ 中,可借助第三方库(如 Boost 库的boost::any ),或使用 C++17 标准原生支持的std::any------ 二者均能安全存储任意类型的数据。

考虑到本项目的移植性 ,这里我们自己实现轻量级的any类

二、Any类的设计思路

需求:

  • 一个连接需要有,请求接收与解析的上下文。
  • 上下文类型不固定,服务器支持多种协议,不同协议上下文结构不同。
  • 结论:得有能保存各种不同类型结构数据的容器。
  • 任务:设计实现一个any类,且它是一个可以存储任意类型的容器。

这里可能多数人的第一反应是,使用类模板,但是这种方法在实例化对象时必须指定数据类型,实例后次类型就固定了,而这里我们需要的是可以存储任意类型的数据显然这是不合理的.

要满足"存储任意类型且无需在实例化时固定类型"的需求,可利用类继承 + 多态 + 类型擦除 的思路设计 Any 类:

Any 类内部嵌套一个抽象基类 (用于"类型擦除",屏蔽具体类型差异),再通过模板子类 承接具体数据的存储。借助多态特性,Any 能间接持有任意类型的对象,且无需在创建 Any 实例时预先指定存储类型。

结合代码理解

三、代码实现

为帮助大家理解如何达到消除类型的效果,下面代码借用AI注释

c 复制代码
#include<iostream>
#include<cassert>
#include<typeinfo>
#include<string>
class Any{
public:
    Any():_content(nullptr){}
    template<class T>
    Any(const T&val):_content(new placeholder<T>(val)){}

    Any(const Any&other):_content(other._content?other._content->clone():nullptr){}//先判空,若不为空就拷贝

    Any&operator=(const Any&other){
       Any(other).Swap(*this);
       return *this;
    }

    template<class T>//赋值重载
    Any&operator=(const T&val){
        Any(val).Swap(*this);
        return *this;
    }

    Any&Swap(Any&other)
    {
        std::swap(this->_content,other._content);
        return *this;
    }
    template<class T>//返回子类对象,存储数据的指针
    T*get(){
        assert(typeid(T)==_content->type());
        return &(((placeholder<T>*)_content)->_val);
    }

    ~Any(){delete _content;}

private:
//holder 是一个纯抽象基类,它的关键特点是:完全不包含任何具体类型的信息,只定义了三个通用接口
//这个基类的作用是 "制定统一标准":无论存储的具体类型是什么(int/string/ 自定义类型)
//对外都必须通过这三个接口交互。从这一层开始,"具体类型" 的细节就被隐藏了。
    class holder{
        public:
        virtual ~holder(){}
        virtual  holder*clone()=0;
        virtual const std::type_info& type()=0;//查看存储类型
    };
//placeholder<T> 是模板类,它继承自 holder,但与具体类型 T 绑定
//向下:直接操作具体类型 T(存储 _val、拷贝 _val);
//向上:通过重写 holder 的接口,将 T 的细节 "包装" 成通用接口。
    template<class T>
    class placeholder:public holder{
        public:
        placeholder(const T&val):_val(val){}
        virtual holder* clone(){return new placeholder(_val);}//根据自己克隆一个新的对象
        virtual const std::type_info& type(){return typeid(T);}//获取存储对象类型
        
        T _val;
    };
    holder* _content;
};
//Any 类是最终对外的 "容器",它的核心成员是 holder* _content,这个指针指向 placeholder<T> 实例,但 Any 类本身 完全不知道 T 是什么
//存储时:无论传入 int、string 还是自定义类型,都被 placeholder<T> 封装成 holder*,Any 无需关心 T;
//传递时:Any 对象的拷贝 / 赋值(如 a = b)通过 holder 的 clone() 接口完成,与具体类型无关;
//取值时:才通过 type() 接口校验类型,再转换回 T*------ 但这个 "类型恢复" 是使用者主动指定 T 的结果,Any 本身仍不感知 T。

//测试
// class Test{
//     public:
//     Test()
//     {
//         std::cout<<"构造"<<std::endl;
//     }
//     Test(const Test&t)
//     {
//         std::cout<<"拷贝"<<std::endl;
//     }
//     ~Test()
//     {
//         std::cout<<"析构"<<std::endl;
//     }
// };
// int main()
// {
//     Any a;
//     a=10;
//     int *p=a.get<int>();
//     std::cout<<*p<<std::endl;
//     a=std::string("aaaa");
//     std::string*sp=a.get<std::string>();
//     std::cout<<*sp<<std::endl;

//     Test t;
//     a=t;

//     return 0;
// }
相关推荐
玖笙&2 小时前
✨WPF编程基础【1.1】:XAML文档框架
c++·visualstudio·wpf
吃不胖没烦恼2 小时前
Alibaba Cloud Linux 3 +Docker 部署 ThinkPHP6 (宝塔环境)
linux·运维·docker
努力学习的小廉2 小时前
初识MYSQL —— 数据库基础
android·数据库·mysql
禁默2 小时前
MySQL 表约束实战指南:从概念到落地,守护数据完整性
数据库·mysql
l1t2 小时前
测试duckdb的C插件模板的编译加工和加载
c语言·开发语言·数据库·插件·duckdb
T - mars3 小时前
数据迁移:MySQL => SQL Server
数据库·mysql
数据智能老司机3 小时前
用 C/C++ 从零实现 Redis——简介
c++·redis
骄傲的心别枯萎3 小时前
RV1126 NO.30:RV1126多线程获取音频AI的PCM数据
linux·ffmpeg·音视频·pcm·视频编解码
RIDDLE!3 小时前
Visual Studio使用C++配置OpenCV环境,同时添加模板以4.12为例
c++·opencv·visual studio