Поскольку вопрос задается кем-то, имеющим опыт работы с Java, я буду толковать его в терминах Java. Вы хотите определить универсальный интерфейс, который будет возвращать объект, полученный из T:
template<typename T>
struct getter
{
virtual T* get() = 0; // just for the signature, no implementation
};
Обратите внимание на изменения: функция объявлена виртуальной, так что она будет вести себя полиморфно в производных объектах. Возвращаемое значение - указатель вместо объекта. Если вы сохраняете объект в своем интерфейсе, компилятор нарезает (обрезает неосновную часть возвращаемого объекта) возвращаемое значение. С некоторой магией метапрограммирования (или прибегая к форсированию) вы можете заставить компилятор проверить ограничение, которое T наследует от данного типа.
Теперь вопрос в том, почему вы хотели бы сделать это ... Если вы определяете неуниверсальный интерфейс (абстрактный класс), который возвращает Thing по указателю, вы можете просто получить ту же семантику проще:
struct Thing {};
struct AnotherThing : public Thing {};
struct getter
{
virtual Thing* get() = 0;
};
struct AnotherGetter : public getter
{
virtual AnotherThing* get() { return 0; }
};
struct Error : public getter
{
int get() { return 0; } // error conflicting return type for get()
};
struct AnotherError : public getter
{
};
int main() {
AnotherError e; // error, AnotherError is abstract (get is still pure virtual at this level)
}
Компилятору потребуются все экземпляры классов, производные от getter, для реализации метода get (), который возвращает указатель Thing by (или ковариантный тип возврата: указатель на класс, производный от Thing). Если производный класс пытается вернуть другой тип, компилятор пометит его как ошибку.
Проблема при публикации заключается в том, что если вы используете интерфейс, то объекты могут обрабатываться только как указатели на базовый класс Thing. Теперь, является ли это проблемой или нет, это другой вопрос ... В общем, если вы правильно спроектировали свою иерархию, вы должны иметь возможность использовать возвращенные объекты полиморфно, не прибегая к понижению.
Обратите внимание, что если вы используете разные методы получения на самом производном уровне в иерархии, каждый метод get()
возвращает наиболее производный элемент из иерархии Thing, в этот момент вам вообще не нужно будет понижать число. Только если вы используете разные геттеры через базовый интерфейс getter
, вы получите один и тот же тип возврата для всех (Thing*
)
Важно отметить, что шаблоны полностью разрешаются во время компиляции. Это означает, что попытка использовать шаблоны для решения необходимости (действительно ли вам это нужно?) Для даункаста не поможет вам, если вы используете различные геттеры через интерфейс (ссылка / указатели на базовый геттер).
Возможно, размещение более подробной информации о вашем конкретном домене, где и как вы собираетесь использовать этот код, может помочь в предоставлении более полезных ответов.