Question

Well this has been giving me grief...

#include <iostream>

class InterfaceClass
{
    public:
    void test()
    {
        std::cout<<"Hello there.\n";
    }
};

template <class T>
class TemplateClass
{
    public:
    T t;
};

class TestClass: public InterfaceClass
{};

class TestInheritor
{
    public:
    TemplateClass < InterfaceClass >* templateInherit;
    InterfaceClass* normalInherit;

    void test()
    {
        normalInherit->test();
        templateInherit->t.test();
    }

};

int main (int nargs, char ** arg)
{

    TestInheritor ti;
    ti.normalInherit = new TestClass; // THIS ONE COMPILES OKAY.

    //ti.templateInherit = new TemplateClass <TestClass>; // COMPILE ERROR.

    // THIS WORKS THOUGH
    TemplateClass <TestClass> * tempClass = new TemplateClass <TestClass>;
    ti.templateInherit=(TemplateClass <InterfaceClass>*)tempClass; // WHY DO I HAVE TO EXPLICITLY CAST?

    // OUTPUT WORKS AS EXPECTED.
    ti.test();

    return 0;
}

The normal inheritance example works just fine. The TestClass is automatically converted to a InterfaceClass. However, with the template example, it gives a compile error:

error: cannot convert 'TemplateClass<TestClass>*' to 'TemplateClass<InterfaceClass>*' in assignment

In my mind, it is obvious that you can convert TemplateClass<TestClass>* to TemplateClass<InterfaceClass>*... So what am I missing here?

I can fix it by explicitly casting the template class to the base class, I am able to use the inherited test() function without any problem... So why am I required to explicitly cast the template class?

Sorry if that's confusing... It's hard for me to explain this problem.


Okay, I understand the issue a little more. I have decided to add a template to TestInheritor like so:

template <class T2>
class TestInheritor
{
    public:
    TemplateClass < T2 >* templateInherit;
    InterfaceClass* normalInherit;

    void test()
    {
        normalInherit->test();
        templateInherit->t.test();
    }
};

int main (int nargs, char ** arg)
{
    TestInheritor <TestClass> ti;
    ti.normalInherit = new TestClass;
    ti.templateInherit = new TemplateClass <TestClass>;
    ti.test();
    return 0;
}

Probably not the perfect solution, but it works for my purposes.


Ah, and I see your solution:

#include <iostream>

class InterfaceClass
{
    public:
    void test()
    {
        std::cout<<"Hello there.\n";
    }
};

class TestClass: public InterfaceClass
{};



template <class T>
class TemplateClass
{
    public:
    T t;
};

template<>
class TemplateClass<TestClass> : public TemplateClass<InterfaceClass>
{
    public:
};


class TestInheritor
{
    public:
    TemplateClass < InterfaceClass >* templateInherit;
    InterfaceClass* normalInherit;

    void test()
    {
        normalInherit->test();
        templateInherit->t.test();
    }
};

int main (int nargs, char ** arg)
{
    TestInheritor ti;
    ti.normalInherit = new TestClass;
    ti.templateInherit = new TemplateClass <TestClass>;
    ti.test();
    return 0;
}
Was it helpful?

Solution

Consider

class Base
{};

class Derived : public Base
{};

template<typename T>
class TemplateClass
{};

Contrary to what you might think, TemplateClass<Derived> is not a TemplateClass<Base> in the sence of inheritance, so pointers to the former can't be implicitly converted to pointers of the later.

So why does explicitly casting a pointer to TemplateClass<Derived> to a pointer of TemplateClass<Base> compile? Because any pointer of a certain type may be explicitly cast to any pointer of any other type, however there are no guarantees the conversion is valid! You could for instance just as well write

int* i = (int*) new TemplateClass<Derived>;

and it would compile just fine, even though it is clearly an invalid conversion.

Now why does your example work? Sheer luck. At the point a pointer containing an address obtained through an invalid pointer cast gets dereferenced, the program becomes invalid and its bahavior undefined. Anything can happen, including doing what you would expect.

If you want TemplateClass<Derived> to be a TemplateClass<Base> in the sence of inheritance, you can define an specialization of TemplateClass<> stating this relationship explicitly, like the following:

template<>
class TemplateClass<Derived> : public TemplateClass<Base>
{};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top