55

对我来说,C++ 模板使用了鸭子类型的思想,对吗?这是否意味着模板类或方法中引用的所有泛型类型都是鸭子类型?

4

7 回答 7

89

对我来说,C++ 模板是鸭子类型的编译时版本。编译器将编译例如 Class,只要您的 Duck 具有所有需要的类型,它就会实例化一个类。

如果某些地方不正确(例如缺少复制构造函数),则编译失败。当您调用具有非鸭子类型的函数时,真正的鸭子打字中的对应物是失败的。在这里它会在运行时发生。

于 2011-08-03T08:09:18.513 回答
18

鸭子打字的意思是,“如果它像鸭子一样嘎嘎叫,像鸭子一样走路,那么它就是一只鸭子”。它在计算机科学中没有正式的定义供我们比较 C++。

当然,C++ 与(例如)Python 不同,但它们都有隐式定义接口的概念。用作 Python 函数参数的对象所需的接口是函数对其执行的任何操作。用作 C++ 模板参数的类型所需的接口是模板对该类型的对象所做的任何事情。这就是相似性,也是评估 C++ 模板的依据。

此外,由于模板参数推导,在 C++ 中您可以尝试传递任何旧对象,编译器会判断它是否可以实例化函数模板。

一个区别是,在 C++ 中,如果参数不嘎嘎作响,那么编译器就是对象。在 Python 中,只有运行时对象(并且仅当函数被实际调用时,如果代码中有条件)。这是对象/类型所要求的接口性质的差异——在 C++ 中,模板要求特定表达式有效,或者不需要。在 Python 中,必要的有效表达式可以依赖于早期必要表达式的运行时值。因此,在 Python 中,您可以请求一个可以大声或安静地嘎嘎叫的物体,如果它大声嘎嘎叫,它也需要走路。在 C++ 中,你可以通过条件来做到这一点dynamic_cast,如果卷是编译时常量,你可以做模板专业化,但你可以'quack_volume()返回loud。当然,在 Python 中,所需的接口可能并不是真正“必需的”——如果方法不存在,则行为是抛出异常,如果发生这种情况,可能会记录并保证调用者的行为。

取决于您是否定义“鸭子类型”,以便这种差异意味着 C++ 没有它。

于 2011-08-03T09:07:18.050 回答
15

对我来说,C++ 模板使用了鸭子类型的思想,对吗?

不,C++ 模板用于实现通用代码。也就是说,如果您的代码可以使用多种类型,则不必为每种类型复制它。像这样的事情,std::vector并且std::list是这方面的明显例子。C++ 模板已被滥用于做其他事情,但通用性是其初衷。

这是否意味着模板类或方法中引用的所有泛型类型都是鸭子类型?

不,它们只是“普通”类型,就像 C++ 中的所有其他类型一样。在模板实际实例化之前,它们是未知的。

但是,模板可用于实现诸如鸭子类型之类的东西。迭代器就是一个例子。考虑这个函数:

template<class InputIterator, class OutputIterator>
    OutputIterator copy(InputIterator first, InputIterator last,
                        OutputIterator result)
{
    while (first!=last) *result++ = *first++;
    return result;
}

请注意,该copy函数可以接受任何类型的参数,以及它实现不等式运算符、取消引用运算符和后缀自增运算符。这可能与您在 C++ 中的鸭子类型一样接近。

于 2011-08-03T08:02:48.590 回答
6

不完全是。Duck 类型(动态类型风格)永远不会产生编译时类型错误,因为它们只是没有任何类型。使用模板,在实例化模板之前您没有类型。一旦你这样做了,变量就有不同的类型,你确实会得到编译时错误。

此外,对于鸭子类型,您可以让一个变量指向不同类型的对象,因为变量只是没有类型。这在模板中是不可能的——一旦你实例化它们,变量就会有一个特定的类型。

但是,它们是相似的,因为约束是隐含的:只检查实际使用的特征。与多态指针相反,实际类型并不重要。

于 2011-08-03T08:02:36.343 回答
4

是的,有点-例如,如果 typeX具有AddRef()Release()并且QueryInterface()具有适当签名的方法,则可以将其用作具有CComPtr模板类的 COM 对象。但这不是完整的鸭子类型 - 仍然对参数强制执行类型检查。

于 2011-08-03T08:00:14.597 回答
2

不,这是一个不同的概念。鸭子类型是一种找出动态类型容器类型的方法。C++ 模板不是动态类型的,它们使用特定类型进行实例化。

于 2011-08-03T08:01:40.107 回答
1

维基百科涵盖了这一区别

于 2011-08-03T08:30:36.323 回答