Ну, это дало мне горе …
#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;
}
Обычный пример наследования работает просто отлично. TestClass автоматически преобразуется в InterfaceClass. Однако, с примером шаблона, он дает ошибку компиляции:
error: cannot convert 'TemplateClass<TestClass>*' to 'TemplateClass<InterfaceClass>*' in assignment
На мой взгляд, очевидно, что вы можете преобразовать TemplateClass<TestClass>*
в TemplateClass<InterfaceClass>*
… Так чего мне здесь не хватает?
Я могу исправить это путем явного приведения класса шаблона к базовому классу, я могу без проблем использовать унаследованную функцию test () … Так почему я должен явно приводить класс шаблона?
Извините, если это сбивает с толку … Мне сложно объяснить эту проблему.
Хорошо, я понимаю проблему немного больше. Я решил добавить шаблон в TestInheritor следующим образом:
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;
}
Возможно, не идеальное решение, но оно работает для моих целей.
Ах, и я вижу ваше решение:
#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;
}
Рассматривать
class Base
{};
class Derived : public Base
{};
template<typename T>
class TemplateClass
{};
Вопреки тому, что вы могли бы подумать, TemplateClass<Derived>
это не TemplateClass<Base>
в смысле наследования указатели на первое не могут быть неявно преобразованы в указатели на более поздние.
Итак, почему явно приведение указателя к TemplateClass<Derived>
на указатель TemplateClass<Base>
компилировать? Поскольку любой указатель определенного типа может быть явно приведен к любому указателю любого другого типа, однако нет никаких гарантий, что преобразование действительно! Вы могли бы, например, так же хорошо написать
int* i = (int*) new TemplateClass<Derived>;
и он скомпилируется просто отлично, хотя это явно недопустимое преобразование.
Теперь, почему ваш пример работает? Счастливой случайности. В тот момент, когда указатель, содержащий адрес, полученный посредством неверного приведения указателя, разыменовывается, программа становится недействительной и ее поведение не определено. Все может случиться, в том числе делать то, что вы ожидаете.
Если ты хочешь TemplateClass<Derived>
быть TemplateClass<Base>
в смысле наследования вы можете определить специализацию TemplateClass<>
с явным указанием этой связи, например:
template<>
class TemplateClass<Derived> : public TemplateClass<Base>
{};
Других решений пока нет …