I need to parse an XML and create objects in C++ that correspond to the XML elements, and also pack the attributes of the XML elements into those objects as properties. The XML elements/attributes and the corresponding C++ classes/properties inherit from a base object that has properties common with the derived objects.
I was thinking to use a base class for the common properties and derived classes would only need to define the object-specific properties. However, someone told me that using the standard polymorphism is not a good idea here because the solution is not generic enough – adding/changing attributes in the XML would require adding/changing the corresponding properties to the C++ classes, which requires changing too much code. A much better and more abstract solution would be to put a dictionary of attributes in the base class and access individual properties by searching the dictionary. I wanted to ask the community whether this suggestion is better for production code.
Below is an example, where vehicle is the base object, and different vehicle types inheriting from it. Vehicle object has the name
and weight
properties that are common for all vehicles. Here is a sample XML fragment:
<car name="Toyota" weight="3500" passengers="4" />
<boat name="Yamaha" weight="3700" draft="16" />
Base class:
class vehicle {
public:
string name;
string weight;
};
Derived classes:
class car : public vehicle {
public:
string passengers;
};
class boat : public vehicle {
public:
string draft;
};
Now, when my parser finds the car and boat elements I instantiate:
boat *b = new boat ();
car *c = new car ();
For the boat I can access all members simply as b->name
, b->weight
, and b->draft
. After the C++ objects are instantiated from the XML, we do the whole bunch of object-specific work on each property, so the goal is not to just simply load XML into the program.
The alternative approach:
#define TAG_XML_ATTRIBUTE_NAME "name"
#define TAG_XML_ATTRIBUTE_WEIGHT "weight"
#define TAG_XML_ATTRIBUTE_PASSENGERS "passengers"
#define TAG_XML_ATTRIBUTE_DRAFT "draft"
. . .
class vehicle {
public:
map<string, string> arguments;
// Get argument by name searching the arguments dictionary.
string GetArgumentOrEmpty(const string& argumentName);
};
class car : public vehicle {
public: // All propeties are in the base class dictionary.
};
class boat : public vehicle {
public: // All propeties are in the base class dictionary.
};
All derived classes have the arguments
map; in order to get a property value we scan the dictionary to find the property by name and then read its value, e.g. GetArgumentOrEmpty(TAG_XML_ATTRIBUTE_WEIGHT)
. CPUs are fast these days, so search the dictionary will not noticeable affect performance. The namespace of elements/attributes goes from structured (as class members) to flat (as #define list), but they will all be in one place. The code is more abstract; although the object processing code gets more complex due to additional indirection, it does not need to change if the attribute name changes; e.g. if passengers
in the XML changes to people
, the #define will look a little awkward, but the code that uses it won’t have to change:
#define TAG_XML_ATTRIBUTE_PASSENGERS "people"
Does the dictionary-based property access method present enough benefit to use it for production code instead of using regular class properties? If so, is it only for this specific XML-parsing case or replacing polymorphism with dictionary search and substituting class properties with string names is a better idea in general?
The dictionary based approach has indeed a couple of advantages:
There are a couple of inconveniences as well:
So you have to make a difficult choice. My advice would be:
If you go for the map, a couple of thoughts:
unordered_map
to avoid too much string comparisons.