当前位置: 首页 > news >正文

【高并发服务器】四、通用类型容器any

文章目录

  • 1、为何需要通用类型
  • 2、`c++17`中的`any`类
  • 3、自主实现`any`类
    • 设计思想
    • 主体框架
    • 函数实现

在这里插入图片描述

1、为何需要通用类型

​ 每一个 Connection 对连接进行管理,最终都不可避免需要涉及到应用层协议的处理,因此在 Connection 中需要设置协议处理的上下文来控制处理节奏。

​ 但是应用层协议千千万,为了降低耦合度,这个协议接收解析上下文就不能有明显的协议倾向,它可以是任意协议的上下文信息,因此就需要一个通用的类型来保存各种不同的数据结构。

​ 在 C 语言中,通用类型可以使用 void* 来管理,但是在 C++ 中,boost 库和 C++17 给我们提供了一个通用类型 any 来灵活使用,如果考虑增加代码的移植性,尽量减少第三方库的依赖,则可以使用 C++17 特性中的 any,或者我们自己来实现。而这个 any 通用类型类的实现其实并不复杂。

​ 下面我们尝试着来实现一下,主要是了解其思想,这样也就避免了第三方库的使用了,如果不想看这部分的话,可以直接看后面 std 中的 any 类使用,都是一样的!

2、c++17中的any

any类的官方文档

​ 要注意的是,因为 any 是属于 c++17 的,所以在编译的时候 需要添加 -std=c++17 选项才能编译通过!

​ 下面我们来看看库中的 any 是如何使用的:

#include <any>
#include <iostream>int main()
{// T* any_cast<class T>() 成员函数用于返回any对象值的地址std::any a = 1;std::cout << a.type().name() << ": " << std::any_cast<int>(a) << std::endl;a = 3.14;std::cout << a.type().name() << ": " << std::any_cast<double>(a) << std::endl;a = true;std::cout << std::boolalpha << a.type().name() << ": " << std::any_cast<bool>(a) << std::endl;// 有误的转型try{a = 1;std::cout << std::any_cast<float>(a) << std::endl;}catch (const std::bad_any_cast& e){std::cout << e.what() << '\n';}// 拥有值a = 1;if(a.has_value())std::cout << a.type().name() << std::endl;// 重置a.reset();if (!a.has_value())std::cout << "no value" << std::endl;// 指向所含数据的指针,对变量取地址使用a = 1;int* i = std::any_cast<int>(&a);std::cout << *i << std::endl;return 0;
}// 执行结果:
[liren@VM-8-7-centos test]$ g++ -o any any.cpp -std=c++17
[liren@VM-8-7-centos test]$ ./any 
i: 1
d: 3.14
b: true
bad any_cast
i
no value
1

3、自主实现any

设计思想

​ 首先我们想,既然要实现一个通用类型的类,首先想到的方案就是使用模板,如下所示:

template <class T>
class Any
{
private:T _content;
};

​ 看起来好像就是通用的,但是使用起来却是这样子的:实例化的时候必须传入模板参数,也就是传入类型,那这和不使用模板也没啥区别呀:

Any<int> a;
Any<double> b;

​ 这并不是我们想要的效果,我们想要的效果是这样子的:

Any a;
a = 10;		// 赋值为整形类型
a = "abcd"; // 赋值为字符串类型
……

​ 所以单单使用模板是解决不了问题的,我们需要换个方案!

​ 新的方案:我们可以在 Any 类中再设计一个类,专门用于保存其它类型的数据,而 Any 类保存的是固定类的对象,如下所示:

class Any
{
private:template <class T>class placeholder // 用来存放其它数据类型的类{T _val;};placeholder* _content; // 上面类的指针
};

​ 此时好像并没有什么变化,还是需要在实例化 Any 的时候传入具体的类型,所以我们还得转变思路,引入多态的思想

​ 我们可以给 placeholder 类设计一个父类 holder,让 Any 类保存 holder 的指针,当 Any 容器需要保存一个数据的时候,只需要通过 placeholder 子类实例化一个特定类型的子类对象出来,让子类对象保存数据!

​ 而当需要操作数据的时候,我们通过传入 placeholder 对象给 Any,本质就是 holder 的指针拿到了 placeholder,就形成了一种多态的机制来操控 placeholder 类!

在这里插入图片描述

class Any
{
private:class holder {...  };template <class T>class placeholder : holder // 用来存放其它数据类型的类{T _val;};holder* _content; // 父类的指针
};

主体框架

​ 结合下面的代码,我们可以看到思路就是实例化一个 Any 类的时候不需要传入一个特定类型参数,因为它会被内部的 _content 指针所拿到,拿到之后其实就与 placeholder 类形成了多态,此时操作 _content 指针就相当于控制 placeholder 类,然后 Any 对象的操作就可以调用 placeholder 类的接口完成操作!

class Any
{
private:class holder{public:virtual ~holder() {}               // 析构函数,父类需要设为虚函数才能正确释放子类virtual std::type_info type() = 0; virtual holder* clone() = 0;      };template <class T>class placeholder : holder{public:placeholder(const T& val) {}	   // 构造函数virtual std::type_info type() = 0; // 用于返回子类中持有的数据类型virtual holder* clone() = 0;       // 用于拷贝生成新的holder对象T _val; // 任意类型的数据};holder* _content; // holder类对象,通过多态方式来操作placeholder对象
public:Any();~Any();template <class T>Any(const T& val);     // 任意类型数据的构造函数Any(const Any& other); // Any对象类型的构造函数template <class T>Any& operator=(const T& val);     // 任意类型数据的赋值重载函数Any& operator=(const Any& other); // Any对象类型的赋值重载函数template <class T>T* get(); // 返回placeholder对象保存的数据的指针
};

函数实现

​ 从上面的主体框架可以看出来,其实要实现的大部分接口都是构造函数等等,并不复杂,要注意的就是 c++ 一些语法特性罢了!

#include <iostream>
#include <typeinfo>
#include <string>class Any
{
private:class holder{public:virtual ~holder() {}               // 析构函数,父类需要设为虚函数才能正确释放子类virtual const std::type_info& type() = 0; virtual holder* clone() = 0;      };template <class T>class placeholder : public holder{public:placeholder(const T& val) : _val(val) {}// 用于返回子类中持有的数据类型virtual const std::type_info& type() { return typeid(T); }// 针对当前的对象自身,克隆出一个新的子类对象virtual holder* clone() { return new placeholder<T>(_val); }       T _val; // 任意类型的数据};holder* _content; // holder类对象,通过多态方式来操作placeholder对象
public:Any() : _content(nullptr) {}~Any() { delete _content; }// 任意类型数据的构造函数template <class T>Any(const T& val) : _content(new placeholder<T>(val))  {}   // Any类型的构造函数Any(const Any& other) { if(other._content == nullptr)_content = nullptr;else_content = other._content->clone();}// 任意类型数据的赋值重载函数template <class T>Any& operator=(const T& val){// 为val构造一个临时的通用容器,然后与当前容器自身进行指针交换,临时对象释放的时候,原先保存的数据也就被释放Any(val).swap(*this);return *this;}// Any类型的赋值重载函数Any& operator=(const Any& other){Any(other).swap(*this);return *this;}// 返回placeholder对象保存的数据的指针template <class T>T* get(){if(_content->type() != typeid(T))return nullptr;return &((placeholder<T>*)_content)->_val;}const std::type_info& type() { return _content->type(); }
private:Any& swap(Any& other){std::swap(_content, other._content);return *this;}
};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* pa = a.get<int>();std::cout << *pa << std::endl;std::cout << a.type().name() << std::endl;a = std::string("lirendada");std::string* sa = a.get<std::string>();std::cout << *sa << std::endl;std::cout << a.type().name() << std::endl;a = Test();Test* ta = a.get<Test>();std::cout << a.type().name() << std::endl;return 0;
}// 执行结果:
[liren@VM-8-7-centos test]$ g++ -o any any.cpp -std=c++11
[liren@VM-8-7-centos test]$ ./any 
10
lirendada
构造
拷贝
析构
析构

在这里插入图片描述

http://www.dtcms.com/a/473316.html

相关文章:

  • linux学习笔记(29)网络编程——服务器客户端 及多进程多线程服务器
  • 边缘服务器 FTP/TFTP 服务搭建与使用(Docker 方式)
  • VMware安装Kali-Linux
  • (6)数据中心、台式(塔式)服务器、机架式服务器、刀片式服务器
  • 为什么 socket.io 客户端在浏览器能连接服务器但在 Node.js 中报错 transport close
  • Arbess CICD实战(10) - 使用Arbess+GitLab实现PHP项目自动化部署
  • 电子商务网站建设的作用广告视频拍摄制作
  • 深圳集团网站建设企业如何快速推广
  • 创新的商城网站建网站建设和优化
  • 学校网站开发背景wordpress 电影 插件
  • 进入官方网站电影网站开发现状
  • 网站建设各模块功能简述如何做网站营销推广
  • 先有域名才可以做网站吗南宁品牌网站建设
  • 温州网站推广效果好公司可以备案几个网站
  • 网页与网站的区别和关系外汇反佣网站建设
  • 青岛网站建设seo优化windows 7 wordpress
  • 沈阳外贸网站制作公司近年网络营销成功案例
  • 自己做一个网站要多少钱长春百度seo排名
  • 网站开发注意事项销售网站免费模板
  • 担保交易网站开发请人做网站需要注意什么
  • 网站导航栏动效怎么做网站建设丨找王科杰上词快
  • 网站首页全屏怎么做建设银行甘肃兰州分行网站
  • 饰品网站模版个人网站如何发布
  • 网站内容收费接送车服务网站怎么做
  • 全国最好的加盟网站网络营销方式有哪些
  • 网站还没建设好可以备案吗网站建设证据保全
  • 校园网站开发需求文字网站更改指定字段
  • 修改wordpress的站点地址做购物网站多少钱 知乎
  • 建筑品牌网站wordpress更换域名301
  • 网站内怎样做关键词有效果网站建设类文章