c++编解码封装

news2024/11/26 12:15:15

多态版编解码

对服务器和客户端的结构体进行序列化然后对数据进行反序列化

案例分析

在这里插入图片描述

代码demo

Codec.h
#pragma once
#include <iostream>

class Codec
{
public:
	Codec();
	virtual std::string encodeMsg();//string是标准库的string类
	virtual void* decodeMsg();

	virtual ~Codec();
};
RequesetCodec.h
#pragma once
#include "Codec.h"
#include "Message.pb.h"
#include <iostream>
using namespace std;

struct RequestInfo
{
	//默认私有的
	int cmd;
	string clientID;
	string serverID;
	string sign;
	string data;
};

class RequestCodec : public Codec
{
public:
	//空对象
	RequestCodec();
	//解码
	RequestCodec(string encstr);//序列化后的字符串
	//编码
	RequestCodec(RequestInfo* info);
	//init函数给空构造准备的
	//解码
	void initMessage(string encstr);
	//编码
	void initMessage(RequestInfo* info);
	//重写父类函数 -> 序列化函数 -> 序列化的字符串
	string encodeMsg();
	//重写父类函数 -> 反序列化函数 -> 返回的是结构体/类对象
	void* decodeMsg();
	~RequestCodec();

private:
	//保存解码的字符串
	string m_encStr;//接收编码
	//要序列化的数据在这个类中,通过这个类进行序列化操作
	RequestMsg m_msg;//protobuf结构体
};
RequesetCodec.h
#include "RequesetCodec.h"
//空对象
RequestCodec::RequestCodec()
{

}
//解码
RequestCodec::RequestCodec(string encstr)
{
	initMessage(encstr);
}
//编码
RequestCodec::RequestCodec(RequestInfo* info)
{
	initMessage(info);
}
//init函数给空构造准备的
//解码
void RequestCodec::initMessage(string encstr)
{
	m_encStr = encstr;
}
//编码
void RequestCodec::initMessage(RequestInfo* info)
{
	m_msg.set_cmdtype(info->cmd);
	m_msg.set_clientid(info->clientID);
	m_msg.set_serverid(info->serverID);
	m_msg.set_sign(info->sign);
	m_msg.set_data(info->data);
}
//重写父类函数 -> 序列化函数 -> 序列化的字符串
string RequestCodec::encodeMsg()
{
	string output;
	m_msg.SerializeToString(&output);
	return output;
}
//重写父类函数 -> 反序列化函数 -> 返回的是结构体/类对象
void* RequestCodec::decodeMsg()
{
	m_msg.ParseFromString(m_encStr);
	return &m_msg;
}
RequestCodec::~RequestCodec()
{

}
test.cpp

触发多态:

#include<iostream>
using namespace std;
#include"Codec.h"
#include"RequesetCodec.h"
#include"RespondCodec.h"
//编码
string encodeMsg(Codec* codec)
{
	return codec->encodeMsg();
}
//解码
void* decodeMsg(Codec* codec)
{
	return codec->decodeMsg();
}
int main()
{
	RequestInfo reqInfo;
	reqInfo.cmd = 9;
	reqInfo.clientID = "Onepiece";
	reqInfo.serverID = "Luffy";
	reqInfo.data = "我是要成为海贼王的男人";
	reqInfo.sign = "hahahahahahaha";
	RequestCodec req(&reqInfo);
	//编码
	string reqmsg = encodeMsg(&req);
	//解码
	RequestCodec reql(reqmsg);
	RequestMsg* reqMsg = (RequestMsg*)decodeMsg(&reql);
	cout << "cmdtype: " << reqMsg->cmdtype()
		<< ", clientID: " << reqMsg->clientid()
		<< ", serverID: " << reqMsg->serverid()
		<< ", data: " << reqMsg->data()
		<< ", sign: " << reqMsg->sign() << endl;

	RespondInfo resInfo;
	resInfo.status = false;
	resInfo.clientID = "黑崎一护";
	resInfo.serverID = "朽木露琪亚";
	resInfo.data = "死神";
	resInfo.seckeyID = 666;
	RespondCodec res(&resInfo);
	//编码
	string resmsg = encodeMsg(&res);
	//解码
	RespondCodec resl(resmsg);
	RespondMsg* resMsg = (RespondMsg*)decodeMsg(&resl);
	cout << "cmdtype: " << resMsg->status()
		<< ", clientID: " << resMsg->clientid()
		<< ", serverID: " << resMsg->serverid()
		<< ", data: " << resMsg->data()
		<< ", sign: " << resMsg->seckeyid() << endl;
}

在这里插入图片描述

工厂模式版编解码

工厂模式(用到多态)

工厂模式的作用

工厂模式的作用是用来创建对象的,那么创建对象的工作实际上是交给了某一个去做。

简单工厂模式–只需1个工厂类

工厂: 使用一个单独的类来做创建实例的过程, 这就是工厂。
简单工厂:把对象的创建放到一个工厂类中,通过参数来创建不同的对象。
特点:

  • 缺点:每添一个对象,就需要对简单工厂进行修改(尽管不是删代码,仅仅是添一个switch case,但仍然违背了“不改代码”的原则)
  • 优点:去除了与具体产品的依赖, 实现简单。
# 简单工厂模式的使用:
1. 创建一个工厂类
2. 在这个类中提供一个公共的成员方法
	- 创建对象, 一般情况下创建某些实现多态的子类对象
	- 返回这个对象的地址

案例

// 通过创建工厂类, 添加工厂函数, 创建对象
// 两个编解码的子类
class RequestCodec : public Codec	// 编解码请求数据
class RespondCodec : public Codec	// 编解码响应数据
/*
	知识点:
		做条件判断的时候, if..else if .. else 效率比 switch 低
		如果判断的情况比较少使用 if .. else
		如果情况比较多, 建议使用 switch
*/
// 创建工厂类, 创建编解码对象
//demo1
class Factory
{
public:
    Factory();
    ~Factory();
    // 工厂函数, 创建对象
    // flag==1 -> RequestCodec
    // flag==2 -> RespondCodec
    Codec* createObject(int flag)
    {
        // 判断
        if(flag == 1)
        {
            RequestCodec* req = new RequestCodec();
        	return req;
        }
        else if(flag == 2)
        {
            RequestCodec* res = new RespondCodec();
            return res;
        }
    }
}
//demo2
class Factory
{
public:
    Factory();
    ~Factory();
    // 工厂函数, 创建对象
    // flag==1 -> RequestCodec
    // flag==2 -> RespondCodec
    Codec* createObject(int flag)
    {
        Codec* c = NULL;
        // 判断
        if(flag == 1)
        {
            c = new RequestCodec();
        }
        else if(flag == 2)
        {
            c = new RespondCodec();
        }
        return c;
    }
}

工厂类的使用:

// 1. 创建工厂类对象
Factory* fac = new Factory;
// 2. 通过工厂函数创建编解码对象
Codec* c = fac->createObject(1);
// 3. 编码
string str = c->encoceMsg();

上面这个案例并没有满足需求,假设子类又多了一个,又要在工厂类进行添加---->这是改原来写好的代码

工厂模式–需要N个工厂类

工厂方法:每种产品由一种工厂来创建,一个工厂保存一个new
特点:基本完美,完全遵循 “不改代码”的原则

# 工厂模式流程
1. 创建一个工厂类的基类
2. 在这个基类中定义一个虚函数 -> 创建对象的方法
3. 创建子工厂类(编解码的基类有多少子类, 就创建多少个子工厂类)
	- 每个编解码的子类, 都对应一个工厂类
4. 在子工厂类中重写工厂类基类中的虚函数

工厂类的使用:

// 两个编解码的子类
class RequestCodec : public Codec
class RespondCodec : public Codec
class TestCodec : public Codec	// 编解码响应数据

使用:

// 创建工厂类的基类
class BaseFactory
{
public:
    BaseFactory();
    ~BaseFactory;
    virtual Codec* createObject()
    {
        return NULL;
    }
}
// 工厂类子类
class RequestFactory : public BaseFactory
{
public:
    RequestFactory();
    ~RequestFactory;
    Codec* createObject()
    {
        return new RequestCodec;
    }
}
class RespondFactory : public BaseFactory
{
public:
    RespondFactory();
    ~RespondFactory;
    Codec* createObject()
    {
        return new RespondCodec;
    }
}
class TestFactory : public BaseFactory
{
public:
    TestFactory();
    ~TestFactory;
    Codec* createObject()
    {
        return new TestCodec;
    }
}

这样就不需要修改原来的代码,只需要添加新的子类就行了
工厂模式使用

// 1. 创建工厂类对象
BaseFactory* fac = new RespondFactory;
// 2. 得到了编解码对象
Codec* c = fac->createObject();
// 3. 编码
string str = c->encodeMsg();

工厂模式实况

工厂类的基类 demo

#pragma once
#include "Codec.h"

class CodecFactory
{
public:
	CodecFactory();
	virtual Codec* createCodec();
	virtual ~CodecFactory();
};

工厂类的子类.h demo

#pragma once
#include "CodecFactory.h"
#include "Codec.h"
#include "RequesetCodec.h"
#include <iostream>

class RequestFactory : public CodecFactory
{
public:
	RequestFactory(std::string enc);
	RequestFactory(RequestInfo* info);
	Codec* createCodec();
	~RequestFactory();

private:
	bool m_flag;
	std::string m_encStr;
	RequestInfo* m_info;
};

工程类的子类.cpp demo

#include "RequestFactory.h"
RequestFactory::RequestFactory(std::string enc) //: CodecFactory()
{
	m_flag = false;
	m_encStr = enc;
}
RequestFactory::RequestFactory(RequestInfo* info)//:CodecFactory()
{
	m_flag = true;
	m_info = info;
}
Codec* RequestFactory::createCodec()
{
	Codec* codec = NULL;
	if (m_flag)
	{
		codec = new RequestCodec(m_info);
	}
	else
	{
		codec = new RequestCodec(m_encStr);
	}
	return codec;
}
RequestFactory::~RequestFactory()
{

}

main.cpp

#include <iostream>
#include "RespondCodec.h"
#include "RespondCodec.h"
#include "Codec.h"
#include "RequestFactory.h"
#include "RespondFactory.h"
using namespace std;

int main()
{
	// 数据编码
	RequestInfo info{ 1, "client", "server", "x00911", "hello, world" };//结构体初始化
	CodecFactory* factory = new RequestFactory(&info);
	Codec* codec = factory->createCodec();
	string str = codec->encodeMsg();
	cout << "序列化数据: " << str << endl;
	delete factory;
	delete codec;

	// 数据解码
	factory = new RequestFactory(str);
	codec = factory->createCodec();
	RequestMsg* r1 = (RequestMsg*)codec->decodeMsg();
	cout << "cmdtype: " << r1->cmdtype()
		<< ", clinetID: " << r1->clientid()
		<< ", serverID: " << r1->serverid()
		<< ", sign: " << r1->sign()
		<< ", data: " << r1->data() << endl;
	delete factory;
	delete codec;

	cout << endl << "=========================" << endl;

	RespondInfo resinfo{ 1, 999, "luffy", "zoro", "change world 666 !" };
	factory = new RespondFactory(&resinfo);
	codec = factory->createCodec();
	str = codec->encodeMsg();
	delete factory;
	delete codec;

	factory = new RespondFactory(str);
	codec = factory->createCodec();
	RespondMsg* r2 = (RespondMsg*)codec->decodeMsg();
	cout << "status: " << r2->status()
		<< ", seckeyID: " << r2->seckeyid()
		<< ", clinetID: " << r2->clientid()
		<< ", serverID: " << r2->serverid()
		<< ", data: " << r2->data() << endl;

	delete factory;
	delete codec;
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2228290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WPF拖拽交互全攻略及实现自定义拖拽控件及数据交换技巧解析

目录 1. 基本概念2 . 实现拖拽功能概述需要要实现基本的拖放&#xff0c;完成以下任务&#xff1a;其他操作 示例3.1 设置拖拽源&#xff0c;拖拽开始3.2 设置拖拽效果DragDropEffects 3.3 设置放置目标&#xff0c;处理拖拽数据拖拽输入DragEnter事件DragOver事件拖拽离开Drag…

【jvm】为什么Xms和Xmx的值通常设置为相同的?

目录 1. 说明2. 避免性能开销3. 提升稳定性4. 简化配置5. 优化垃圾收集6. 获取参数6.1 代码示例6.2 结果示例 1. 说明 1.-Xms 和 -Xmx 参数分别用于设置堆内存的初始大小&#xff08;最小值&#xff09;和最大大小。2.在开发环境中&#xff0c;开发人员可能希望快速启动应用程…

c++提示函数可能不安全This function or variable may be unsafe

现象 编译c代码时&#xff0c;经常会出现如下提示&#xff0c;大约有几种情况&#xff1a; 现象一 warning C4996: strcpy: This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online …

苹果ANE引擎以及使用编程方法介绍

苹果ANE引擎介绍 大多数新款iPhone和iPad都配备了一个神经网络引擎&#xff08;Neural Engine&#xff09;&#xff0c;这是一种特殊的处理器&#xff0c;能让机器学习模型的运行速度变得非常快。然而&#xff0c;关于这个处理器具体如何工作&#xff0c;公众所知的信息并不多…

Python | Leetcode Python题解之第516题最长回文子序列

题目&#xff1a; 题解&#xff1a; class Solution:def longestPalindromeSubseq(self, s: str) -> int:n len(s)dp [[0] * n for _ in range(n)]for i in range(n - 1, -1, -1):dp[i][i] 1for j in range(i 1, n):if s[i] s[j]:dp[i][j] dp[i 1][j - 1] 2else:dp…

网络编程 UDP编程 Linux环境 C语言实现

UDP编程 1. 一般UDP编程 UDP传输特点&#xff1a;非面向连接、不可靠的、无序的 报式传输 支持组播和广播 UDP应用数据最大长度建议&#xff1a;MTU(以太网分组数据的最大长度)1500 - 20(IP头) - 8(UDP头) 1472Bytes 客户端&#xff1a;支持两种形式的代码编写: 1. 不定向…

高压线路覆冰厚度测量,输电线路微波覆冰监测装置守护电网安全

随着北方地区正式步入冬季&#xff0c;气温急剧下降&#xff0c;高压线路覆冰现象日益严重&#xff0c;给电网安全带来了前所未有的挑战。近日&#xff0c;在东北某省&#xff0c;由于连续低温天气&#xff0c;多条高压线路遭受了严重的覆冰侵袭&#xff0c;这不仅极大地加重了…

Java面试经典 150 题.P88. 合并两个有序数组(001)

本题来自&#xff1a;力扣-面试经典 150 题 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 题解 class Solution {public void merge(int[] nums1, int m, int[] nums2, …

基于安卓Android的健身系统APP(源码+文档+部署+讲解)

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 选题不知道怎么选 不清楚自己适合做哪块内容 都可以免费来问我 会持续一直更新下去 有问必答 一键收藏关注不迷路 源码获取&#xff1a;https://pan.baidu.…

中电信翼康工程师:我在 Apache SeaTunnel 社区的贡献之旅

贡献者Github ID&#xff1a;luckyLJY 文章整理&#xff1a;曾辉 Apache SeaTunnel 作为一款强大的数据同步和转换工具&#xff0c;凭借其部署易用性、容错机制、数据源支持、性能优势、功能丰富性以及活跃的社区支持&#xff0c;成为了数据工程师们不可或缺的利器。 因其具有的…

offset Explorer连接云服务上的kafka连接不上

以上配置后报连接错误时&#xff0c;可能是因为kafka的server.properties配置文件没配置好&#xff1a; 加上面两条配置&#xff0c;再次测试连接&#xff0c;成功 listeners和advertised.listeners

使用Python来下一场雪

具体效果&#xff1a;&#xff08;大雪缓缓下落&#xff09; 完整代码&#xff1a; import pygame import random# 初始化 Pygame pygame.init()# 设置窗口 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption("下雪…

k8s 1.28.2 集群部署 Thanos 对接 MinIO 实现 Prometheus 数据长期存储

文章目录 [toc]什么是 ThanosThanos 的主要功能Thanos 的架构组件Thanos 部署架构SidecarReceive架构选择 开始部署部署架构创建 namespacenode-exporter 部署kube-state-metrics 部署Prometheus Thanos-Sidecar 部署固定节点创建 label生成 secretMinIO 配置etcd 证书 启动 P…

13、基于AT89C52轮询方式扫描按键proteus仿真

一、仿真原理图: 二、仿真效果: 三、相关代码: 1、main主函数: void main(void) { unsigned char ll; VariableInit(); while(1) { value = keyScan(); display(); …

春季测试 2023 我的题解

T1 涂色游戏 这道题目还是比较简单的 容易发现&#xff0c;位于 ( x i , y i ) (x_i,y_i) (xi​,yi​) 的格子的颜色只取决于 ​ x i x_i xi​ 行与 y i y_i yi​ 列的颜色。 这时候可以想到开两个数组&#xff0c;分别存储列与行的绘画信息&#xff0c;然后发现前后的互相…

magic-api简单使用二:自定义返回结果

背景 在上一章 中我们学习了搭建项目和导入文件&#xff0c; 这二天稍微有点时间&#xff0c;研究下这个magic-api的写法。 后续如果需要维护或者更改&#xff0c;也能在项目中尽快上手。 今天我们主要学习自定义返回结果&#xff0c;当然也可以使用官方的。不需要任何更改。…

“启动智能制造引擎 推动新质生产力发展”高峰论坛在京成功举办

在智能制造技术的助力下,北京经开区的智能制造产业稳步发展。2024年10月25日,北京电子科技职业学院图书馆暨北京经济技术开发区公共图书馆举办一场以“启动智能制造引擎 推动新质生产力发展”为主题的高峰论坛于北京亦庄经开区盛元书院圆满落幕。此次论坛为北京经开区智能制造产…

Java 异常处理(6/30)

目录 Java 异常处理 1. 什么是异常 2. 异常处理的关键字 2.1 try-catch 语句 2.2 多个 catch 块 2.3 finally 块 2.4 throw 和 throws 3. 自定义异常 4. 异常处理的最佳实践 总结与后续 Java 异常处理 在软件开发中&#xff0c;异常处理&#xff08;Exception Handl…

ubuntu22.04安装向日葵

1、下载deb安装包 进入官网下载图形版本&#xff1a;https://sunlogin.oray.com/download/linux?typepersonal 2、命令行安装 sudo chmod x 文件名.deb sudo dpkg -i 文件名.deb 3、开始报错的看这里&#xff01; 首先展示一下安装成功的效果图&#xff1a; 接下来是我安…

小米手机投屏到Windows笔记本电脑的3个方法,随便选一个

方法一&#xff1a;Windows系统自带的投屏功能 Windows系统本身的功能很多&#xff0c;其中一项就是接收别的电脑或手机的投屏。 操作步骤一&#xff0c;在Windows电脑里进入【设置】&#xff0c;点击【系统】&#xff0c;往下翻页&#xff0c;找到【投影到此电脑】。 如果这…