zoukankan      html  css  js  c++  java
  • C++

      现在,假想需要设计一个 JSON 类型数据结构,善于提前构思的你,大致想了想:

    Object {
        "key": Boolean,
        "key": Number,
        "key": String,
        "key": Array,
        "key": Object
    }
    

      嗯,看起来没什么问题,开始设计...没写多久,可能考虑到这种情况:

    Object {
        "key": [Object{}, Object{}, ...]
    }
    

      这意味着类结构大概变成这样:

    class Object {
        bool boolean;
        double number;
        std::string string;
        std::vector<Object> array;
        Object object;
    }
    

      当然,你很明白 Object 是一个多键值对,于是改一下:

    class Value {
    public:
        bool boolean;
        double number;
        std::string string;
        std::vector<Object> array;
        Object object;
    };
    
    class Object {
    public:
        std::vector<std::pair<std::string key, Value value>>> objects;
    }
    

      这是一个互相包含的类,对于 C++ 而言,显然编译器会报错,因为 Value 类中使用了未定义的 Object 类型,而此处编译器无法确定你的 Value 类成员变量的大小。

      不过,你还是有办法,使用指针,并向前声明 Object 类:

    class Object;
    
    class Value {
    public:
        bool boolean;
        double number;
        std::string string;
        std::vector<Object> array;
        Object* object;
    };
    
    class Object {
    public:
        std::vector<std::pair<std::string, Value>>> objects;
    }

      可是,这时又会有个小问题,如果你想要像下面这样使用接口

    Object object;
    
    object["Window"] = Value(Object("Color", Value("blue")));
    std::cout << object["Window"].GetObject()["Color"].GetString();
    

      是不可行的,因为 Value 中 object 是指针,当重载 [] 运算符后,只能这样使用它:

    Object object;
    
    object["Window"] = Value(new Object("Color", Value("blue")));
    std::cout << object["Window"].GetObject()->operator[]("Color").GetString();
    

      看起来很怪异,如果将就着用倒也没什么,但换一个位置会好些:

    class Value;
    
    class Object {
    public:
        std::vector<std::pair<std::string, Value*>>> objects;
    }
    
    class Value {
    public:
        bool boolean;
        double number;
        std::string string;
        std::vector<Object> array;
        Object object;
    };
    

      用法变为:

    Object object;
    
    object["Window"] = new Value(Object("Color", Value("blue")));
    std::cout << object["Window"]->GetObject()["Color"]->GetString();
    

      如果想彻底去掉包含指针这个问题需要做一些工作,通过中间类继承 + friend class 来去掉可以做到十分完美的样子,参见微软开源的 cpprestsdk json 代码实现。

      当然,或许还有其他办法解决这个问题,但我觉得最优美且最能体现 C++ 风格的方法就是继承 + 友元类。

      这篇博客仅仅想写下当初写 JSON 构造 / 分析器时遇到的这个类结构设计问题,尽管这里只提到了向前类声明的使用,实际上,除开数字值的类型问题(int64 -> int32 -> double 溢出问题),性能问题,当时还学到了很多 C++ 的用法。(以后可能会较少用 C++ 了)

      最后给一个极简的 JSON 构造器实现:

    #include <iostream>
    #include <vector>
    #include <string>
    
    class Value;
    
    class Boolean {
    private:
    	bool _boolean;
    public:
    	Boolean()
    		: _boolean() {}
    	Boolean(bool val)
    		: _boolean(val)
    	{
    
    	}
    
    	bool GetVal() const {
    		return _boolean;
    	}
    
    	void SetVal(bool val)
    	{
    		_boolean = val;
    	}
    };
    
    class Number {
    private:
    	double _number;
    public:
    	Number()
    		: _number() {}
    	Number(int val)
    		: _number(val)
    	{
    
    	}
    	Number(double val)
    		: _number(val)
    	{
    
    	}
    
    	double GetVal() const {
    		return _number;
    	}
    
    	void SetVal(double val) {
    		_number = val;
    	}
    };
    
    class String {
    private:
    	std::string _string;
    public:
    	String() {}
    	String(const char* val)
    		: _string(val)
    	{
    
    	}
    	String(std::string val)
    		: _string(val)
    	{
    
    	}
    	std::string GetVal() const {
    		return _string;
    	}
    
    	void SetVal(std::string val)
    	{
    		_string = val;
    	}
    };
    
    class Array {
    private:
    	std::vector<Value> _array;
    public:
    	Array()
    		: _array()
    	{
    	}
    	Array(std::vector<Value> val)
    		: _array(val)
    	{
    
    	}
    	std::vector<Value> GetVal() const
    	{
    		return _array;
    	}
    
    	void SetVal(std::vector<Value> val)
    	{
    		_array = val;
    	}
    };
    
    
    class Object {
    	std::vector<std::pair<std::string, Value*>> _elements;
    private:
    	typedef std::vector<std::pair<std::string, Value*>>::iterator iterator;
    
    	iterator find_iter_by_key(std::string key)
    	{
    		return std::find_if(_elements.begin(), _elements.end(), [&key](const std::pair<std::string, Value*>& p) { return p.first == key; });
    	}
    
    public:
    	Object() {}
    	Object(std::string key, Value* value)
    		: _elements{ {key, value} }
    	{
    
    	}
    
    	Value*& operator[](std::string key)
    	{
    		return GetValue(key);
    	}
    
    	size_t Size() const
    	{
    		return _elements.size();
    	}
    
    	Value*& GetValue(std::string key)
    	{
    		auto iter = find_iter_by_key(key);
    		if (iter == _elements.end())
    			return _elements.insert(iter, std::pair<std::string, Value*>(key, nullptr))->second;
    		return iter->second;
    	}
    };
    
    class Value {
    	Boolean v_boolean;
    	Number v_number;
    	String v_string;
    	Array v_array;
    	Object v_object;
    
    public:
    	Value()
    		: v_boolean(), v_number(), v_string(), v_array(), v_object()
    	{
    	}
    
    	Value(const Value & value)
    	{
    		*this = value;
    	}
    
    	Value(bool value)
    		: v_boolean(value), v_number(), v_string(), v_array(), v_object()
    	{
    
    	}
    	Value(int value)
    		: v_boolean(), v_number(value), v_string(), v_array(), v_object()
    	{
    
    	}
    	Value(double value)
    		: v_boolean(), v_number(value), v_string(), v_array(), v_object()
    	{
    
    	}
    	Value(std::string value)
    		: v_boolean(), v_number(), v_string(value), v_array(), v_object()
    	{
    
    	}
    	Value(std::vector<Value> value)
    		: v_boolean(), v_number(), v_string(), v_array(value), v_object()
    	{
    	}
    	Value(Boolean value)
    		: v_boolean(value), v_number(), v_string(), v_array(), v_object()
    	{
    
    	}
    	Value(Number value)
    		: v_boolean(), v_number(value), v_string(), v_array(), v_object()
    	{
    
    	}
    	Value(String value)
    		: v_boolean(), v_number(), v_string(value), v_array(), v_object()
    	{
    
    	}
    	Value(Array value)
    		: v_boolean(), v_number(), v_string(), v_array(value), v_object()
    	{
    
    	}
    	Value(Object value)
    		: v_boolean(), v_number(), v_string(), v_array(), v_object(value)
    	{
    
    	}
    
    	bool GetBoolean() const
    	{
    		return v_boolean.GetVal();
    	}
    
    	double GetNumber() const
    	{
    		return v_number.GetVal();
    	}
    
    	int GetIntNumber() const {
    		return (int)v_number.GetVal();
    	}
    
    	std::string GetString() const
    	{
    		return v_string.GetVal();
    	}
    
    	std::vector<Value> GetArray() const
    	{
    		return v_array.GetVal();
    	}
    
    	Object GetObject() const
    	{
    		return v_object;
    	}
    
    	Value& GetValue()
    	{
    		return *this;
    	}
    
    
    };
    
    int main()
    {
    	Object object("test", new Value(Object("abc", new Value(123))));
    	object["color"] = new Value(Array{ std::vector<Value>{ Value(String("red")), Value(String("orange")), Value(String("yellow")) } });
    	std::cout << object["test"]->GetObject()["abc"]->GetIntNumber() << '
    ';
    	for (auto i : object["color"]->GetArray())
    		std::cout << i.GetString() << " ";
    	return 0;
    }

      输出:

    123
    red orange yellow
    

      

  • 相关阅读:
    像调试java一样来调试Redis lua
    微言限流
    性能测试遭遇TPS抖动问题
    你所不知道的堆外缓存
    基于JMH的Benchmark解决方案
    基于FastJson的通用泛型解决方案
    你所不知道的日志异步落库
    mac上配置java开发环境
    你所不知道的库存超限做法
    服务器一般达到多少qps比较好[转]
  • 原文地址:https://www.cnblogs.com/darkchii/p/12563533.html
Copyright © 2011-2022 走看看