C++ 模板而不是接口的缺点是什么?(C+;+;)

C++ 模板而不是接口的缺点是什么?(C+;+;),c++,templates,C++,Templates,我通常使用接口实现以下实现,但是在了解了模板之后,我觉得模板对于实现多态性非常有用。(如Ruby duck打字) #包括 类动物{ 公众: 虚空cry()=0; }; 犬类:公共动物{ virtualvoidcry(){std::cout差别不大,因为在第一个示例中,您有一个编译器可以自动内联的平凡函数 也就是说,action(&dog);可以内联到((动物*)&dog)->cry(),它比狗更有可能变成狗。cry() 在做出任何与此相关的重大决定之前,要做的是在你使用的几个C++编译器上尝试这

我通常使用接口实现以下实现,但是在了解了模板之后,我觉得模板对于实现多态性非常有用。(如Ruby duck打字)

#包括
类动物{
公众:
虚空cry()=0;
};
犬类:公共动物{

virtualvoidcry(){std::cout差别不大,因为在第一个示例中,您有一个编译器可以自动内联的平凡函数

也就是说,
action(&dog);
可以内联到
((动物*)&dog)->cry()
,它比狗更有可能变成
狗。cry()

<>在做出任何与此相关的重大决定之前,要做的是在你使用的几个C++编译器上尝试这个问题,并研究编译输出。 其次,可以将
action
函数移到类中,这样我们就不用
action(&dog)
而只做
dog.action()
。这个
action
成员函数可以作为
Animal::action
开始生命:只作为基类中的一个实用函数。如果我们发现一个表达式
dog.action()
正在通过虚拟机执行不必要的调度,并希望消除它,然后我们有机会编写一个
Dog::action
函数,该函数将隐藏
Animal::action
。然后
Dog.action()
表达式将使用该函数

最后,仅使用非虚拟成员函数和模板还有一个缺点:所有分派都是静态的(在编译时确定)。这在运行时确定对象类型的情况下无法工作。例如,假设我们有:

Animal *a = createAnimalFromConfigFile();
action(a);
运行时配置文件的语法告诉程序制作狗、猫或其他东西。我们在编译时不知道配置文件可能包含什么;编译程序的用户可以编辑它

createAnimalFromConfigFile
必须在其中包含一些选择语句,以便在构建不同动物的不同代码段之间进行分支,如:

if (type == "dog") // type field parsed from file
  return new Dog(/* parameters from file */);
else if (type == "cat")
  return new Cat(/* ... */)
else ...

我们将OOP风格与虚拟函数结合使用,这样我们就可以通过在单独编码的类型情况下进行大量条件切换来限制这种丑陋代码的扩散。一旦我们将所有的Duck(或
Duck
-s)都排成一行来构造对象,之后,我们就有了对它的基类引用(一个指向
动物的指针或引用
),只需使用虚拟方法的框架以一种通用的方式使用它即可。(或者这就是闪亮的OOP手册所说的。)

这就像问使用螺丝刀而不是锤子有什么好处。编译过程中需要解析模板的实际类型。多态方法调用-不要。例如,考虑到您的示例,您可能会有:
Animal*pAnimal=createDog?(Animal*)new Dog:(Animal*)new Cat;action(pAnimal);
,它将被正确调度。您将如何处理模板?尝试将同一模板的多个不同专门化放入同一个
std::vector
if (type == "dog") // type field parsed from file
  return new Dog(/* parameters from file */);
else if (type == "cat")
  return new Cat(/* ... */)
else ...