13

在模板鸭子类型和纯虚拟基类继承之间进行选择的准则是什么?例子:

// templates
class duck {
    void sing() { std::cout << "quack\n"; }
};

template<typename bird>
void somefunc(const bird& b) {
    b.sing();
}

// pure virtual base class
class bird {
    virtual void sing() = 0;
};

class duck : public bird {
    void sing() { std::cout << "quack\n"; }
}

void somefunc(const bird& b) {
    b.sing();
}
4

5 回答 5

12

使用模板鸭子类型,您正在执行静态多态性。因此,你不能做类似的事情

std::vector<bird*> birds;
birds.push_back(new duck());

但是,由于您依赖于编译时类型,因此效率更高(没有虚拟调用意味着没有动态调度(基于动态类型))。

于 2010-07-23T16:25:06.730 回答
3

如果您可以广泛传播事物的“模板性质”,那么模板(“编译时鸭子类型”)可以为您提供惊人的速度(避免隐含在虚函数调用中的“间接级别”)虽然也许以内存占用为代价(理论上,良好的 C++ 实现可以避免与模板相关的内存开销,但我不太相信这样高质量的编译器一定会在您需要移植的所有平台上可用;- )。因此,至少从务实的角度来看,这是一种速度/内存的权衡。如果您正在执行的操作像 I/O 一样超级慢,那么避免虚拟调用所获得的相对微小的速度增益可能对您的用例并不重要。

于 2010-07-23T16:25:57.167 回答
2

编译时间与运行时间。如果要编译时绑定,则需要使用模板。如果您在编译时不知道类型,则应使用虚拟继承。

于 2010-07-23T18:52:26.500 回答
0

它们是两种完全不同的东西。一个不能替代另一个。模板函数提供了一个通用操作somefunc(),它适用于整个类型,而不仅仅是鸟类。其参数的类型必须在编译时知道。虚拟方法提供特定于鸟类的运行时多态操作。参数 ( ) 的确切类型this不需要在编译时知道。

由于它们提供不同的功能,并且彼此不冲突,因此您很少需要在两种方法之间做出决定。确定您需要什么功能,明智的方法将是显而易见的。它甚至可能是两者的结合。

(顺便说一句,“鸭子打字”一词在这里被滥用。这两种方法都不是鸭子打字。你应该从你的 C++ 词典中删除这个短语。)

于 2010-07-23T17:25:12.587 回答
-2

@John 是对的。如果你有两个协变类型参数你别无选择,你必须使用模板。面向对象技术提供运行时分派,但它仅适用于其方法最多具有一个变体参数(对象)的类型。

最有趣的问题涉及 N>1 的 N 元关系,因此您通常别无选择,只能使用模板。请检查标准库以查看最常用的技术。

于 2010-11-28T03:34:27.610 回答