It depends on what use the template does with the passed type. If you mean standard containers (e.g. std::vector
, std::map
and so on) then the answer is no. There is no relation at all between std::vector<Animal>
and std::vector<Dog>
even if in your class hierarchy dogs derive from animals.
You cannot put a Dog
in an std::vector<Animal>
... C++ uses copy semantic and you would incur in what is called "slicing" that means that your Dog
instance will lose any member that is not also present in the base Animal
class.
However in general it's of course well possible for a template to use the type in different ways that will allow therefore accept instances of derived classes. For example in the following code the template MethodCaller
can be instantiated with a type but using an instance of a derived type and correctly handling late binding dispatch. This is possible because the MethodCaller
instance only holds a reference and doesn't make a copy of the object.
#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);
}
It is also possible to implement the Stack
class as you want...
#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>();
}
Note that in the implementation I've used an std::vector
for keeping pointers to animals and therefore to avoid the slicing problem. I've been using a template method to be able to accept derived types in the push call.
Also note that when popping animals you must provide what is the class and if it's a wrong one (e.g. you pop out a Crocodile
when the top element on the stack is a Dog
) you will get a bad_cast
exception at runtime.