I'm trying to implement data classes derived from one base class.
And each derived classes has different data fields.
So the each instances have to be handled differently depending on type of data instance.
I made one example code for this.
#include <iostream>
#include <algorithm>
#include <boost/shared_ptr.hpp>
using namespace std;
enum DataTypes{
EMPTY = 0,
TYPE1,
TYPE2
};
class DataBase {
public:
DataBase():type(EMPTY){}
virtual ~DataBase(){}
DataTypes getType() const{return type;}
protected:
DataBase(DataTypes n):type(n){}
DataTypes type;
};
class DataType1 :public DataBase {
public:
DataType1(): DataBase(TYPE1){}
string data_for_class1;
};
class DataType2 :public DataBase {
public:
DataType2(): DataBase(TYPE2){}
string data_for_class2;
};
boost::shared_ptr<DataBase> createInstance(int n){
boost::shared_ptr<DataBase> p;
if(n == 1){
p.reset(new DataType1);
boost::shared_ptr<DataType1> temp = boost::static_pointer_cast<DataType1>(p);
temp->data_for_class1 = "[Data for DataType1]";
}
else if(n==2){
p.reset(new DataType2);
boost::shared_ptr<DataType2> temp = boost::static_pointer_cast<DataType2>(p);
temp->data_for_class2 = "[Data for DataType2]";
}
return p;
}
int main() {
boost::shared_ptr<DataBase> p = createInstance(2);
try{
/*
if p is an instance of DataType1
process p as DataType1;
else if p is an instance of DataType2
process p as DataType2;
else
throw exception("Empty data");
*/
}catch(runtime_error& e){
cerr<<e.what()<<endl;
}
return 0;
}
The commented part in try-catch expression should be filled.
After thinking hard,I got two possible solutions.
type
field in DataBase
classFor doing this,
DataBase
class should have type
field. DataBase
are responsible for calling constructor(DataBase(DataTypes n)
) with appropriate parameter.Code :
switch (p->getType()){
case TYPE1:
{
cout<<"This is an instance of DataType1"<<endl;
boost::shared_ptr<DataType1> temp = boost::static_pointer_cast<DataType1>(p);
cout<<temp->data_for_class1<<endl;
}
break;
case TYPE2:
{
cout<<"This is an instance of DataType2"<<endl;
boost::shared_ptr<DataType2> temp = boost::static_pointer_cast<DataType2>(p);
cout<<temp->data_for_class2<<endl;
}
break;
case EMPTY: default:
throw runtime_error("Data is empty");
}
dynamic_cast
for all derived classesIn contrast to case1, this method
DataBase
to have additional field for type-checking. dynamic_cast
is good way of doing this.Code :
if(boost::dynamic_pointer_cast<DataType1>(p)){
cout<<"This is an instance of DataType1"<<endl;
boost::shared_ptr<DataType1> temp = boost::static_pointer_cast<DataType1>(p);
cout<<temp->data_for_class1<<endl;
}
else if(boost::dynamic_pointer_cast<DataType2>(p)){
cout<<"This is an instance of DataType2"<<endl;
boost::shared_ptr<DataType2> temp = boost::static_pointer_cast<DataType2>(p);
cout<<temp->data_for_class2<<endl;
}
else{
throw runtime_error("Data is empty");
}
Both of the above ways, I could get working codes. But I'm not sure this is proper way of doing this.
If the above codes have potential problems or if you know a better solution, please share your nice idea.
Thanks.
There is also solution #3 with a virtual getType
(and no type
field stored in the base).
class DataBase {
public:
DataBase() {}
virtual ~DataBase() {}
virtual DataTypes getType() { return EMPTY; } // or '= 0;'
};
class DataType1 :public DataBase {
public:
//...
DataTypes getType() { return TYPE1; };
};
class DataType2 :public DataBase {
public:
//...
DataTypes getType() { return TYPE2; };
};