According to Is it bad practice to use Inheritance to associate methods with a basic container?, I know it is bad to inherit form std containers, mainly because std containers are not designed to be inherited.
However, I found a scenario that I don't know if it is reasonable to inherit a vector, for example, I have an object that the data needs to be loaded from json using rapidjson:
class School{
private:
std::string name;
int age;
std::vector<Student> students;
std::vector<Teacher> teachers;
public:
void jsonToObj(rapidJson::Value& value){
this->name=value["name"].GetString();
this->age=value["age"].GetInt();
this.students.clear();
for(auto itr=value["students"].Begin();itr!=value["students"].End();++itr){
Student student;
student.jsonToObj(itr.GetObject());
this->students.push_back(student);
}
this.teachers.clear();
for(auto itr=value["teachers"].Begin();itr!=value["teachers"].End();++itr){
Teacher teacher;
teacher.jsonToObj(itr.GetObject());
this->teachers.push_back(teacher);
}
}
}
I found I need to copy the long for loop for each vector currently:
this.students.clear();
for(auto itr=value["students"].Begin();itr!=value["students"].End();++itr){
Student student;
student.jsonToObj(itr.GetObject());
this->students.push_back(student);
}
So I create a helper class to convert the array:
template<class T>
class VectorHelper<T>{
public:
void jsonToObj(rapidJson::Value& value,std::vector<T>& vector){
vector.clear();
for(auto itr=value.Begin();itr!=value.End();++itr){
T t;
t.jsonToObj(itr.GetObject());
vector.push_back(t);
}
}
}
So that I can use the VectorHelper in School as the following:
class School{
private:
std::string name;
int age;
std::vector<Student> students;
std::vector<Teacher> teachers;
public:
void jsonToObj(rapidJson::Value& value){
this->name=value["name"].GetString();
this->age=value["age"].GetInt();
VectorHelper<Student>::jsonToObj(value["students"],this->students);
VectorHelper<Teacher>::jsonToObj(value["teachers"],this->teachers);
}
}
The code above seems look better, however, I found it has still a disadvantage: it has bad readability because "this->students" appears at the right hand side, which I want the properties appear in left hand side, so I create a class inherit from vector:
template<class T>
class MyVector : public std::vector<T>{
public:
void jsonToObj(rapidJson::Value& value){
this->clear();
for(auto itr=value.Begin();itr!=value.End();++itr){
T t;
t.jsonToObj(itr.GetObject());
this->push_back(t);
}
}
}
Now the vector in School class becomes MyVector:
class School{
private:
std::string name;
int age;
MyVector<Student> students;
MyVector<Teacher> teachers;
public:
void jsonToObj(rapidJson::Value& value){
this->name=value["name"].GetString();
this->age=value["age"].GetInt();
this->students->jsonToObj(value["students"]);
this->teachers->jsonToObj(value["teachers"]);
}
}
which the vector also uses active record pattern (the jsonToObj method is inside the vector), and the class properties appear at the left of the line, which I think has better readability, for example: easier to see if any class properties missed.
So my question is, is the scenario above a reason to inherit from vector?
students->jsonToObjlooks misnamed. You are converting a json array tostd::vector.jsonToObja free function in a namespaceVectorHelper, the call in stake would still look likeVectorHelper::jsonToObj<Student>(value["students"],this->students);template <typename T> std::vector<T> jsonToVector(rapidJson::Value&)? Then you can just writethis->students = jsonToVector<Student>(value["students"]);and it looks just like the other two assignments above it.