这取决于模板对传递的类型的用途。如果您指的是标准容器(例如std::vector、std::map 等),那么答案是否定的。 std::vector<Animal> 和 std::vector<Dog> 之间根本没有任何关系,即使在您的类层次结构中,狗来自动物。
您不能将Dog 放在std::vector<Animal> 中... C++ 使用复制语义,您会招致所谓的“slicing”,这意味着您的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 来保持指针 指向动物,从而避免切片问题。我一直在使用模板方法来接受推送调用中的派生类型。
还要注意,当弹出动物时,您必须提供类是什么,如果它是错误的(例如,当堆栈上的顶部元素是 Dog 时,您会弹出 Crocodile),您将得到 @987654338 @运行时异常。