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

近期在做一个有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;
}

172440_P2nk_2375158.png

可以实现不同类的成员同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;
}


174826_UfdG_2375158.png

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

转载于:https://my.oschina.net/u/2375158/blog/420248

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值