0

I'd like to cast a base class pointer to a derived one in order to take advantage of some methods unique to the derived class. Here's an Ideone of a simple example that works:

template<typename A>
class Base {};

template<typename A, typename B>
class Derived : public Base<A> {
public:
    void doSomething() {}
};

int main() {
    Base<int>* foo = new Derived<int, double>;
    static_cast<Derived<int, double>*>(foo)->doSomething();
    return 0;
}

Now, the problem is that my foo is actually a member of a templated class,

template<typename A>
class Container
{
public:
    Base<A>* foo;
};

and at the time I cast, I don't know what A is:

int main() {
    Container<int> container;
    container.foo = new Derived<int, double>;

    // a lot of code later...
    static_cast<Derived< /* ??? */ , double>*>(container.foo)->doSomething();

    return 0;
}

Then I thought this might be possible if I could somehow store what A is in my base class, like

template<typename A>
class Base
{
public:
    static type template_type = A; // made-up syntax
};

so that I can refer to it like

static_cast<Derived<container.template_type, double>*>(container.foo)->doSomething();

but according to this question it's not possible to store types in C++.

How do I achieve this cast without knowing A?

That is, how do I cast a specialized base pointer to a derived pointer that specializes on an additional template parameter? In less technical terms, I just want to take a Base pointer and tack on the other specialization necessary to form the Derived pointer.

Community
  • 1
  • 1
Andrew Cheong
  • 29,362
  • 15
  • 90
  • 145
  • Surely you know what A is, since you have an object of type Base that you're trying to cast? – ajclinto Sep 14 '14 at 18:18
  • That's what I keep thinking, but it's weird, I see no way to know `A` in my set up. Let me look at it again and perhaps edit in a tiny bit more to show why. – Andrew Cheong Sep 14 '14 at 18:19
  • @ajclinto - Nope, you were right. I figured it out. I had the same hunch but didn't see it before. I _thought_ my utility function designed to print elements of `Container` had to be generic, which is why I thought I didn't know what `A` would be. But after tracing through code I realized that this utility function only gets a chance to be called on `Container`s of a specific type `A`, so even though it felt wrong before, it's actually correct to hardcode the one type `A` that it will print. Logic works! Closing this question. – Andrew Cheong Sep 14 '14 at 18:29
  • I'll close this question but not delete it in case anyone ever comes around wanting to do the same thing. Solution: inspect your code more closely and see if you're trying to make something generic that isn't meant to be / ever will be generic. – Andrew Cheong Sep 14 '14 at 18:30

1 Answers1

1

Usually it is not wise to do an up-cast and there is usually a better design that you may use to avoid the need of up-cast at all, but if you really need it, then you may use dynamic_cast to do this.

this operator try to convert from one type to another type dynamically and if conversion is not possible, it will return nullptr. But remember that it only work for polymorphic types(types that have at least one virtual function) so in this case your Base class must be polymorphic(since you are holding a pointer to base class, you possibly need a virtual destructor to allow delete to work on base pointer and this make Base a polymorphic class).

But to remember a type in C++, you have 2 options:

  • Use typedef:

You may use typedef to hold type information in the class:

template< class A >
class my_class
{
public:
    typedef A    input_type;
};

template< class T >
void do_something(T const& t)
{
     typename T::input_type n;
     do_something_on_input_type(n); // possibly overloaded for different input types
}

this approach is really fast and have no overhead in runtime, but you can use it only in cases when you want to do something in compile time. and if the type of pointer is not determined until runtime this approach is not useful.

Using this you can actually hold type information with the class:

class Base { virtual std::type_info const& get_type() const = 0; };
class Child : public Base
{
    virtual std::type_info const& get_type() const { return typeid(Child);
    void child_specific_function() { /**/ }
}
class ChildOfChild : public Child
{
    virtual std::type_info const& get_type() const { return typeid(ChildOfChild); }
    // ...
};

void do_something(Base* base)
{
    if (base->get_type() == typeid(Child))
    {
        static_cast<Child*>(base)->child_specific_function();
    }
}

This sound really interesting but, it is only useful when you know exact type of the object and it does not work for derived types, so this approach work for Child but not for ChildOfChild

BigBoss
  • 6,904
  • 2
  • 23
  • 38