Jie Liu
Jie Liu

Reputation: 107

Cast the type dynamically in multiple inheritance scenario

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

Answers (1)

Remy Lebeau
Remy Lebeau

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);

Live Demo

Upvotes: 1

Related Questions