Reputation: 107
Assume there is a template class that is an abstract interface to keep track a series of data.
template<typename T>
class SeriesData
{
virtual T valueAt(int i) const = 0;
};
I decide to use vector to store the data so I inherits from it, I also add a function to add value to series.
template<typename T> class MySeriesData : public SeriesData<T>
{
T valueAt(int i) const {return values_[i];}
void add(const T& value) {values_.push_back(value);}
private:
std::vector<T> values_;
};
The class that is going to use the series of data.
template<typename T>
class AT
{
public:
T data() const {return data_;}
void setData(SeriesData<T>* data) {delete data_; data_ = data;}
private:
SeriesData<T> *data_;
};
class IT : public AT<int>
{
};
class ST : public AT<string>
{
};
There is also a class that implements some common logic:
class A
{
public:
A(){}
virtual ~A() {}
protected:
void common() {cout << "A common" << endl;}
};
And there are two classes, each of which inherits from IT
and ST
, and both of which need to inherit from A
. I want to have them inherit from A because there are so much common logic.
class Numbers : public A , public IT
{
};
class Strings : public A , public ST
{
};
In the main logic, I will use a pointer in type of A to dynamically create the instance of either Numbers or Strings based on the type client wants.
A* item;
if(type == NUMBER)
item = new Numbers();
else if(type == STRING)
item = new Strings();
I can just use item to do those common things, which is good.
item->common();
However, for those logic that are related to AT. I would need to check the real type and then do cast.
item->common();
if(type == NUMBER)
{
IT* itemNumber = static_cast<Numbers*>(item);
itemNumber->setData(new MySeries<int>());
}
else if(type == STRING)
{
ST* itemString = static_cast<Strings*>(item);
itemString->setData(new MySeries<string>());
}
.....
if(type == NUMBER)
{
//Have to cast from A to the a type of AT first
Numbers* itemNumber = static_cast<Numbers*>(item);
//Another conversion
MySeries<int>* numberValues = (MySeries<int>*)itemNumber->data();
numberValues->add(1);
}
else if(type == STRING)
{
Strings* itemString = static_cast<Strings*>(item);
MySeries<string>* stringValues = (MySeries<string>*)itemString->data();
stringValues->add("1");
}
This is annoying when the code is full of these if...else
or switch...case
, especially when there are more and more types.
Is it possible to cast the type more smartly? It will be nice if I can always (or in most of cases) use pointer of A to do all the stuffs.
Upvotes: 0
Views: 78
Reputation: 595377
You can wrap the type
-dependent operations in helper functions that are stored in lookup tables keyed by type
, for example:
std::map<int, A*(*)()> makeAMap;
makeAMap[NUMBER] = []() -> A* { return new B; };
makeAMap[STRING] = []() -> A* { return new C; };
...
std::map<int, void(*)(A*)> getFuncMap;
getFuncMap[NUMBER] = [](A *item){ static_cast<B*>(item)->get(); };
getFuncMap[STRING] = [](A *item){ static_cast<C*>(item)->get(); };
...
A* item = makeAMap[type]();
...
item->common();
getFuncMap[type](item);
Upvotes: 1