I am writing a parsing library, where I have public headers shared with some larger software. One of the headers is a data-containing object, let’s call it DataObject. The object has some fields of type size_t, float, and std::string.
The way the parser is designed, it will expect setters to take a string value as an argument, and the setter should try to convert the value to the designated data type. If the conversion fails, the parser will exit and return an error message that an unexpected type was found.
However, these setters should not be in the public header available to the larger software. It should remain clean and only contain setters with arguments matching the data type of said member.
To solve this I have created a child struct of DataObject, let’s call it DataObjectChild, that is NOT public and available to the larger software, in which I put my setters needed by the parser.
Simple example:
DataObject.h
class DataObject {
public:
void setValue1(size_t value) { this->value1 = value; }
size_t getValue1() { return this->value1; }
void setValue2(size_t value) { this->value2 = value; }
size_t getValue2() { return this->value2; }
private:
size_t value1, value2;
}
DataObjectChild.h
struct DataObjectChild : public DataObject {
void setValue1(std::string value) { this->value1 = std::stoi(value); }
void setValue2(std::string value) { this->value2 = std::stoi(value); }
}
-
Is this commonly used or it is just plain bad practice?
-
If so, does it have a name?
>Solution :
If you would like to expose only this interface:
void setValue1(size_t value);
size_t getValue1();
you could provide an abstract class
class DataObject {
public:
virtual ~DataObject();
virtual void setValue1(size_t value) = 0;
virtual size_t getValue1() = 0;
};
and a factory that gives your users the concrete object with specific implementation
std::unique_ptr<DataObject> createDataObject(args ...);
Or you can use pointer to implementation idiom, then you can allow your user to create the object directly
class DataObject {
public:
void setValue1(size_t value);
size_t getValue1();
private:
std::unique_ptr<DataObjectImpl> _pImpl;
};
//cpp
class DataObjectImpl {}; // implement it here
void DataObject::setValue1(size_t value) {
_pImpl->whatever();
// ....
}
size_t DataObject::getValue1() {
_pImpl->whatever();
// ....
}
In case of your non-polymorphic example it would be difficult to generalize and hide the implementation.