Это зависит от того, как шаблон использует передаваемый тип. Если вы имеете в виду стандартные контейнеры (например, std::vector
, std::map
и т. Д.), То ответ отрицательный. Между std::vector<Animal>
и std::vector<Dog>
вообще нет никакой связи, даже если в вашей классовой иерархии собаки происходят от животных.
Вы не можете поместить Dog
в std::vector<Animal>
... C ++ использует семантику копирования, и вы будете подвергаться так называемому " нарезке ", что означает, что ваш экземпляр Dog
потеряет любой член, которого также нет в базовом Animal
классе.
Однако в целом, конечно, шаблон может использовать тип по-разному, что позволит, следовательно, принимать экземпляры производных классов. Например, в следующем коде шаблон MethodCaller
может быть создан с типом, но с использованием экземпляра производного типа и правильной обработкой поздней отправки связывания. Это возможно, потому что экземпляр MethodCaller
содержит только ссылку и не создает копию объекта.
#include <stdio.h>
template<typename T>
struct MethodCaller
{
T& t;
void (T::*method)();
MethodCaller(T& t, void (T::*method)())
: t(t), method(method)
{}
void operator()() { (t.*method)(); }
};
struct Animal { virtual void talk() = 0; };
struct Dog : Animal { virtual void talk() { printf("Bark\n"); } };
struct Cat : Animal { virtual void talk() { printf("Meow\n"); } };
struct Crocodile : Animal { virtual void talk() { printf("??\n"); } };
void makenoise(Animal *a)
{
MethodCaller<Animal> noise(*a, &Animal::talk);
noise(); noise(); noise();
}
int main()
{
Dog doggie;
Cat kitten;
Crocodile cocco;
makenoise(&doggie);
makenoise(&kitten);
makenoise(&cocco);
}
Также возможно реализовать класс Stack
, как вы хотите ...
#include <vector>
template<typename T>
struct Stack
{
std::vector<T *> content;
~Stack()
{
for (int i=0,n=content.size(); i<n; i++)
delete content[i];
}
template<class S>
void push(const S& s)
{
content.push_back(new S(s));
}
template<class S>
S pop()
{
S result(dynamic_cast<S&>(*content.back()));
content.pop_back();
return result;
}
private:
// Taboo
Stack(const Stack&);
Stack& operator=(const Stack&);
};
int main()
{
Dog doggie;
Cat kitten;
Crocodile cocco;
Stack<Animal> s;
s.push(doggie);
s.push(kitten);
s.push(cocco);
Crocodile cocco2 = s.pop<Crocodile>();
Cat kitten2 = s.pop<Cat>();
Dog doggie2 = s.pop<Dog>();
}
Обратите внимание, что в реализации я использовал std::vector
для хранения указателей на животных и, следовательно, во избежание проблем с нарезкой. Я использовал шаблонный метод, чтобы иметь возможность принимать производные типы в вызове push.
Также обратите внимание, что при совании животных вы должны указать класс, и если он неправильный (например, вы выдаваете Crocodile
, когда верхний элемент в стеке равен Dog
), вы получите bad_cast
исключение во время выполнения.