31
votes
#include <iostream>
using namespace std;

class Base {
public:
  Base() {};
  ~Base() {};
};

template<class T>
class Derived: public Base {
  T _val;
public:
  Derived() {}
  Derived(T val): _val(val) {}
  T raw() {return _val;}
};

int main()
{
  Base * b = new Derived<int>(1);
  Derived<int> * d = b;
  cout << d->raw() << endl;
  return 0;
}

I have some polymorphism problem right now and the code above summarizes everything. I created a Base class pointer and I put the pointer of a new derived template class in it. Then I created a new pointer for the derived template class and I want it to have the reference the base class pointer points to. Even though Base pointer (b) points to a Derived, the reference cannot be passed to Derived class pointer (d) because there's no known conversion from Base * to Derived<int> * (as what the compiler says).

So is there a trick or an alternative way to be able to do it? Thanks in advance.

3
The conversion you describe is known as a downcast.ComicSansMS

3 Answers

56
votes

You must change the base type to be polymorphic:

class Base {
public:
    Base() {};
    virtual ~Base(){};
};

To cast from some supertype to some derived type, you should use dynamic_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = dynamic_cast<Derived<int> *>(b);

Using dynamic_cast here checks that the typecast is possible. If there is no need to do that check (because the cast cannot fail), you can also use static_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = static_cast<Derived<int> *>(b);
3
votes

Try this:

Derived<int> * d = static_cast<Derived<int>* >(b);

downside it is, that you can cast class that is instance of Base() and then d->raw() will be undefined (segmentation fault likley). If that can be case, use dynamic_cast and have at least one function ob base virtual (having destructors virtual is essential when working with polmorphism).

Virtual functions are under the hood implemented using pointer on virtual table. This pointer can be also used to identify true type of class. This is used by dynamic_cast to check if this conversion can be done and brings small extra overhead when casted.

2
votes

You can use dynamic_cast

Derived<int> * d = dynamic_cast<Derived<int> *>(b);

If the cast fails (the base pointer does not point to the requested derived type), it returns null.

However, for dynamic_cast to work, your base class must have at least one virtual function. I suggest you make the destructor virtual (this is also prevents other potential problems deleting your objects).

Use of dynamic_cast may indicate bad design in your code.

Note that if you are 100% sure the base pointer, points to your derived type, then you may replace it with static_cast, which is slightly faster. Personally I prefer the extra safety check in general.