文档章节

C++遍历类中所需成员转为JSON字符串并通过字符串修改成员

s
 smallLang
发布于 2015/05/26 18:12
字数 2008
阅读 257
收藏 0

近期在做一个有15个相关数据库三层架构类的项目,要运用到遍历15个类中特定成员的名称和值,把它们转为JSON字符串;同时可以通过输入JSON字符串修改类中特定成员的值。下面是三种解决方案:

    0.想在网上找一个这样的库来实现(可惜没找着)

    1.笨而可靠的办法:为每个类写一个转为JSON字符串函数,再写一个JSON字符串转实体类的函数;(笨是笨了点,但是灰常可靠)

    2.为15个类写一个Base类,让转JSON字符串函数和JSON字符串转实体类的函数在Base类中实现,同时争取在15个类中尽量少做修改;

下面对方案2的俩函数进行思路扩展(按照俺已经实现的思路哈,其他分叉思路就略过不提了,回忆太费脑细胞了):

有类,比如:

Typedef long long BigInt;
class A
{
public:
    TestCls1(void);
    ~TestCls1(void);
Public(private):
    byte* c;
    char * i;
    std::string m_str1;
    std::string m_str2;
 //   int LL;
//    long lint;
    BigInt bint; 
Private:
    std::string m_str;
};

1.转JSON字符串函数的思路(以类A为例):

JSON字符串例子:

std::string_jsonStr="{\"c\":\"hehe\",\"m_str1\":\"123456789123456789\",\"m_str2\":\"000\",\"bint\":123456789123456789, \"i\":\"abc\"}"

JSON字符串中的内容分别对应类A中特定成员的变量名称和值;

 

首先,遍历范围控制---在15个类中添加一对约束宏JSON_START和JSON_END来控制范围;如下:

class A
{
public:
    TestCls1(void);
    ~TestCls1(void);
Public(private): 
JSON_START;//开始遍历的宏
    byte* c;
    char * i;
    std::string m_str1;
    std::string m_str2;
    std::string m_str4;
    int LL;
    long lint;
    BigInt bint; 
JSON_END;//结束遍历的宏
Private:
    std::string m_str;
};

    JSON_START和JSON_END声明在哪里呢?很显然要在Base父类中

然后,如何获取范围中的变量名称-----通过浏览和判断头文件的方式来取得约束宏JSON_START和JSON_END中的变量名称

    那么接下来的问题,如何获取15个不同类的头文件呢?答案:__FILE__;最好定义在JSON_END这个宏中,既然声明了一个宏,白用白不用啦(也可以在JSON_START中)

    如何获取变量名称呢?这个比较简单啦,打开头文件,行获取文本内容,字符串查找啦,合理利用空格啦等等只要实现就好,最好把该成员的类型名也获取到,因为后面要用到(俺那个BigInt类型就是利用空格,最后对于具有诸如unsiged char/long long 两个单词类型说明不适用所规定的,最好把算法做完善)。

 

接下来,如何获取值-----如果你能通过实体类的首地址来访问和修改类中所有成员的值的话,那么接下来的思路不说你也知道啦;但是如果你还不知道这样的方式,那么请认真阅读下面的代码:

#include <string>
#include <iostream>
 
using namespace std;
 
#define STR_ADVANCESIZE 16          //string给字符串预留的内存大小
 
int _tmain(int argc, _TCHAR* argv[])
{
    int strAddrToMem_LengthAddr =0; //string首地距其成员长度的地址差
    int strAddrToMem_C_strAddr = 0; //string首地距其成员内容的地址差
 
    std::string testStr1 = "12345"; //这个string长度小于16
    std::string testStr2 = 
        "1234567891234567";         //这个string长度大于等于16
 
    //首先,获取string字符串长度距离首地址的差值
    for(int i=0; i<sizeof(std::string); i++)
    {
        if(*(int*)((int)&testStr1+i) ==
            testStr1.length())      //获取strAddrToMem_LengthAddr
        {
            strAddrToMem_LengthAddr = i;
            break;
        }
    }
 
    cout<<*(int*)((int)&testStr1+strAddrToMem_LengthAddr)
    <<" "<<testStr1.length()<<endl; //看看这俩值是不是一样的?
 
    *(int*)((int)&testStr1+
        strAddrToMem_LengthAddr) = 
        10;                         //修改一下
 
    cout<<*(int*)((int)&testStr1+strAddrToMem_LengthAddr)
    <<" "<<testStr1.length()<<endl; //看看testStr1.length()修改了吗?
 
    //然后获取string中字符串内容距离首地址的差值
    for(int i=0; i<sizeof(std::string); i++)
    {
        if(!strcmp((char*)((int)&testStr1 + i), 
            testStr1.c_str()))      //长度小于的testStr1比较一下
        {
            strAddrToMem_C_strAddr = i;
            break;
        }
    }
 
    cout<<(char*)((int)&testStr1 + strAddrToMem_C_strAddr)
        <<endl;                     //看见什么了吗?
 
    memcpy((char*)((int)&testStr1 + strAddrToMem_C_strAddr),
        "haha", 5);                 //修改一下
 
    cout<<testStr1.c_str()<<endl;   //又看见什么了吗?
 
    //那长度大于string预分配的大小呢?看下面就明白啦
 
    cout<<(char*)(*(int*)((int)&testStr2 + strAddrToMem_C_strAddr))
        <<endl;                     //希望你能明白^_^
 
    return 0;
}

    现在已经知道,可以通过实体类首地址来访问和修改成员的值;但是我们不可能知道我们要遍历的特定成员在类中哪个位置啊?所以不能利用类首地址。但是以此为借鉴,我们就在类中自定义一个我们自己的变量int json_begin,并将其添加到开始宏JSON_START中,如下

#define JSON_START int\

    json_begin;\

    这下,子类中就安插了一个获取需要遍历成员堆栈中的最小地址& json_begin,然后利用类型(前面浏览头文件的时候不是叫最好获取吗?)所占字节数,以此递增,可获得接下来的成员的地址及值,直至结束宏。该实现在继承Base类时需要传入& json_begin的值到Base类的构造函数中;作为一个已知量,然后在Base类中实现访问和修改子类中的成员。

 

2.json字符串修改实体类中成员的值函数思路扩展:

    其实嘛,和上一步是相反的,所以不再解释, 嘿嘿~~~~;

    要注意几点:string类空间大小的判断,指针的判断和释放,指针的内存分配;

 

再再接下来,看看俺自己的代码及效果(Base类省去,太多啦):

1.  先声明一个子类,继承Base类,添加宏JSON_START和JSON_ENDTestCls.h

#pragma once
#include "CTranverseBase.h"
#include <iostream>
 
using namespace std;
 
namespace TESTCLS
{
    class TestCls: public CTranverseBase
    {
    public:
        TestCls(void);
        ~TestCls(void);
 
    public:
        JSON_START;
        byte* c;
        char * i;
        std::string m_str1;
        std::string m_str2;
        BigInt bint;
        JSON_END;
 
    private:
        
        int j;
        std::string m_str3;
        std::string m_str;
    };
}

  1. 2.  在main函数中的调用:

#include "CTranverseBase.h"
#include "TestCls.h"
 
#include <string>
 
void TestStringCls();
 
int _tmain(int argc, _TCHAR* argv[])
{
    std::string jsonStr =    "{\"c\":\"hehe\",\"m_str1\":\"123456789123456789\",\"m_str2\":\"000\",\"bint\":123456789123456789, \"i\":\"abc\"}";
 
    TestCls mmm;
    CTranverseBase *baseC = &mmm;
    cout<<baseC->MemDataToJsonStr()<<endl;//转json字符串
 
    baseC->JsonStrToMemValue(jsonStr);// json字符串修改实体类成员
 
cout<<baseC->MemDataToJsonStr()<<endl;//转json字符串,再次打印看修改没
 
    return 0;
}

可以实现不同类的成员同JSON之间的转换:

继续添加另外一个类,同样继承Base类:

#pragma once
#include "../TraverseClassByMemory/CTranverseBase.h"
class TestCls1:public CTranverseBase
{
public:
 TestCls1(void);
 ~TestCls1(void);
public:
 JSON_START;
 std::string m_str5;
 int __int;
 std::string m_str1;
 int LL;
 long lint;
 BigInt bint;
 std::string xxxxstr2;
 std::string exstr3;
 JSON_END;
 int otherArg;
private:
 //int m;
 int j;
 std::string m_str4;
 std::string m_str;
};


  
2.在main.cpp中添加调用新类的代码和测试代码:(调用就一俩句,测试的话就多啦,要看效果嘛)
#include "stdafx.h"
#include "../TraverseClassByMemory/CTranverseBase.h"
#include "TestCls.h"
#include "TestCls1.h"
#include <iostream>
#include <string>
using namespace std;
void TestStringCls();
int _tmain(int argc, _TCHAR* argv[])
{
 //TestStringCls();
 std::string jsonStr = 
  "{\"c\":\"hehe\",\"m_str1\":\"123456789123456789\",\"m_str2\":\"000\",\
  \"bint\":123456789123456789, \"i\":\"abc\",\"m_str3\":\"ddd\",\"m_str5\":\
  \"llllllllllll\"}";
 std::string jsonStr1 = 
  "{\"lint\":202,\"m_str1\":\"123456789123456789\",\"xxxxstr2\":\"000\",\
  \"bint\":123456789123456789, \"__int\":101,\"exstr3\":\"ddd\",\"m_str5\":\
  \"llllllllllll\",\"LL\":111222}";
 CTestCls mmm;
 TestCls1 kkk;
 
 CTranverseBase *baseC = &mmm;
 CTranverseBase *baseC1 = &kkk;
 cout<<"子类的特定成员名称和初始化值转为JSON字符串:\n\t"<<baseC->MemDataToJsonStr()<<endl;
 
 baseC->JsonStrToMemValue(jsonStr);
 cout<<"通过jsonStr修改子类的特定成员值后转为JSON字符串:\n\t"<<baseC->MemDataToJsonStr()<<endl;
 cout<<"mmm类中成员的当前值:\n\tmmm.c = "
  <<mmm.c<<"\n\tmmm.i = "
  <<mmm.i<<"\n\tmmm.m_str1 = "
  <<mmm.m_str1.c_str()<<"\n\tmmm.m_str2 = "
  <<mmm.m_str2.c_str()<<"\n\tmmm.bint = "
  <<mmm.bint<<endl;
 cout<<"\tmmm.m_str3 = "<<mmm.m_str3.c_str()<<endl;
 cout<<"\tmmm.m_str5 = "<<mmm.m_str5.c_str()<<endl;
 cout<<"子类的特定成员名称和初始化值转为JSON字符串:\n\t"<<baseC1->MemDataToJsonStr()<<endl;
 baseC1->JsonStrToMemValue(jsonStr1);
 cout<<"通过jsonStr修改子类的特定成员值后转为JSON字符串:\n\t"<<baseC1->MemDataToJsonStr()<<endl;
 cout<<"kkk类中成员的当前值:"<<endl;
 cout<<"\tkkk.__int = "<<kkk.__int<<endl;
 cout<<"\tkkk.LL = "<<kkk.LL<<endl;
 cout<<"\tkkk.m_str1 = "<<kkk.m_str1.c_str()<<endl;
 cout<<"\tkkk.m_str5 = "<<kkk.m_str5<<endl;
 cout<<"\tkkk.xxxxstr2 = "<<kkk.xxxxstr2.c_str()<<endl;
 cout<<"\tkkk.exstr3 = "<<kkk.exstr3.c_str()<<endl;
 cout<<"\tkkk.bint = "<<kkk.bint<<endl;
 cout<<"\tkkk.lint = "<<kkk.lint<<endl;
 
 return 0;
}


最后,这是一个由于自己兴趣写的代码;博文是临时发表,难免出错,还请阅者海涵。如果你急需这样的功能来实现你自己的项目,可以联系俺,俺会无偿发给你;但是不包没bug(一般按照俺给的头文件上的要求来做的话,都不会出现bug,也有例外) 嘎嘎。

© 著作权归作者所有

s
粉丝 2
博文 15
码字总数 10148
作品 0
深圳
程序员
私信 提问
C++ Primer Plus(四)——复合类型

只能在定义数组时才能初始化,不能将一个数组赋值给另一个数组,但可以使用下标分别赋值给数组元素,但可以将一个string对象赋值给另一个string对象 如果只对数组的一部分初始化,其他元素自...

吃一堑消化不良
2015/11/06
118
0
STL list链表的用法详解

------------------------------------------------------------------------------- 原来... STL list链表的用法详解 本文以List容器为例子,介绍了STL的基本内容,从容器到迭代器,再到普通...

nao
2014/04/10
289
0
STL 简介,标准模板库

这篇文章是关于C++语言的一个新的扩展——标准模板库的(Standard Template Library),也叫STL。 当我第一次打算写一篇关于STL的文章的时候,我不得不承认我当时低估了这个话题的深度和广度...

AlphaJay
2010/04/20
353
0
Protocol Buffers(1):序列化、编译与使用

目录 序列化与反序列化 Protocol Buffers概览 Protocol Buffers C++ 编译 Protocol Buffers C++ 使用 Protocol Buffers的可读性 参考 Protocol Buffers docs:https://developers.google.com......

Mr-Lee
04/13
0
0
《鸡啄米C++编程入门系列》系列技术文章整理收藏

《鸡啄米C++编程入门系列》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201812.html 文章 鸡啄米:C++编程入门系列之前言 鸡啄米:C++编程入门系列之一(进制...

开元中国2015
2015/06/27
83
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
7
0
用最通俗的方法讲spring [一] ──── AOP

@[TOC](用最通俗的方法讲spring [一] ──── AOP) 写这个系列的目的(可以跳过不看) 自己写这个系列的目的,是因为自己是个比较笨的人,我曾一度怀疑自己的智商不适合干编程这个行业.因为在我...

小贼贼子
昨天
7
0
Flutter系列之在 macOS 上安装和配置 Flutter 开发环境

本文为Flutter开发环境在macOS下安装全过程: 一、系统配置要求 想要安装并运行 Flutter,你的开发环境需要最低满足以下要求: 操作系统:macOS(64位) 磁盘空间:700 MB(不包含 IDE 或其余...

過愙
昨天
6
0
OSChina 周六乱弹 —— 早上儿子问我他是怎么来的

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @凉小生 :#今日歌曲推荐# 少点戾气,愿你和这个世界温柔以待。中岛美嘉的单曲《僕が死のうと思ったのは (曾经我也想过一了百了)》 《僕が死の...

小小编辑
昨天
2.6K
16
Excption与Error包结构,OOM 你遇到过哪些情况,SOF 你遇到过哪些情况

Throwable 是 Java 中所有错误与异常的超类,Throwable 包含两个子类,Error 与 Exception 。用于指示发生了异常情况。 Java 抛出的 Throwable 可以分成三种类型。 被检查异常(checked Exc...

Garphy
昨天
42
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部