There are many similar questions and I found both pro and against reasons to use this pattern so I am asking this here:
I need to make a JSON implementation in C++ (
is there any specific reason why not to do this?
Yes. What you obtain with this, is UB. The problem arises from the std::
containers not supporting polymorphism. They were not designed to be inherited from (no virtual destructor) and this means you cannot write a correct/safe destructor sequence.
Instead, your solution probably should look like this:
namespace XYZ { // <-- cannot have same name as class here
class JSON { };
class object : public JSON {
std::unordered_map<std::string,JSON> values;
public:
JSON& operator[]( const std::string& key );
};
class vector : public JSON {
// same here
};
...
};
I wouldn't recommend to inherit from STL.
Due to performance reasons STL standard containers do not have virtual destructors, thus you cannot handle them polymorphically.
This means that there's no way to use runtime polymorphisim and expect proper desctructors for them.
Inheriting from STL, although is perfectly allowable, most of the times denotes bad design. I would recommend not following the inherits from way but rather has a way:
namespace JSON {
class JSON { };
class object : public JSON
{
std::unordered_map<std::string, JSON> m;
public:
// provide interface to access m.
};
class Vector : public JSON {
std::vector<JSON> v;
public:
// provide interface to access v.
};
...
};
I think it is actually better to wrap it within your own class (i.e. proxy using std as member) since it makes it much more loosely coupled and if you would like to use a different data structure it would be quite easy, since you could simply modify your own class while the std classes should not be modified at all. If the interface of your objects is simple, maybe you should even implement your own interface (to make it easily compatible when you want to use a different data structure from std or boost or whatever suits your needs). Your current implementation is maybe not the best one at mentioned in the comments, but i would still recommend wrapping std uses in your own class (especially in larger applications).
It seems you're thinking that a JSON object is an unordered map, so it should inherit from std::unordered_map
. I think you're making a logical jump here. A JSON object is definitely what you would describe as an example of an "unordered map", but is it really a std::unordered_map
? I wouldn't say so. To say it's an std::unordered_map
suggests that it should share the interface of std::unordered_map
and should be able to be used anywhere that a std::unordered_map
is used. I suggest that the interface of std::unordered_map
is more complex and lower level than you'd want from a JSON object.
On top of this, for the most part the standard library classes are not designed to be used as base classes (especially not if they're then used polymorphically).
Considering these two points, I'd suggest that it makes much more sense for you to represent your JSON classes in terms of the standard library components, but not with an is-a relationship. Instead, use the standard library components as members of the JSON classes.