Search code examples
c++inheritancetemplatesvirtualabstract-class

Accessing a method from a templated derived class without using virtual functions in c++?


How do I get around this? I clearly cannot make the value() method virtual as I won't know what type it is beforehand, and may not know this when accessing the method from b:

class Base
{
public:
    Base() { }
    virtual ~Base() { }
private:
    int m_anotherVariable;
};

template <typename T>
class Derived : public Base
{
public:
    Derived(T value) : m_value(value) { }
    ~Derived() { }

    T value() { return m_value; }
    void setValue(T value) { m_value = value; }
private:
    T m_value;
};

int main()
{
    Base* b = new Derived<int>(5);

    int v = b->value();

    return 0;
}

Compilation errors:

error: 'class Base' has no member named 'value'

Solution

  • This statement:

    int v = b->value();
    

    The variable 'b' is being trated like it is an object of Derived<int>.
    So tell the compiler:

    int v = dynamic_cast<Derived<int>*>(b)->value();
    

    Note: If b is not a Derived<int> the result of the cast is NULL.
    So the following would probably be safer:

    Derived<int>*  d = dynamic_cast<Derived<int>*>(b);
    if (d)
    {
        int v = d->value();
    }
    else
    {
        // Error
    }
    

    Alternatively by using references you get a bad_cast exception thrown:

    // Throw bad_cast on failure.
    Derived<int>& d = dynamic_cast<Derived<int>&>(*b);
    int v = d->value();
    

    Or to be nice and obscrure we can do it one line.

    // Assign v or throw bad_cast exception:
    int v = dynamic_cast<Derived<int>&>(*b).value();
    

    But I think you can achieve what you are trying to do with the boost::any

    int main()
    {
        boost::any   b(5);
    
        int    v = boost::any_cast<int>(b);
    
        b        = 5.6; // double
        double d = boost::any_cast<double>(b);
    }