副标题#e#
object-oriented programming(面向工具编程)的世界是环绕着 explicit interfaces(显式接口)和 runtime polymorphism(执行期多态)为中心的。譬喻,给出下面这个(没有什么意义的)的 class(类)。
class Widget {
public:
Widget();
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other); // see Item 25
...
};
以及这个(同样没有什么意义)的 function(函数),
void doProcessing(Widget& w)
{
if (w.size() > 10 && w != someNastyWidget) {
Widget temp(w);
temp.normalize();
temp.swap(w);
}
}
我们可以这样谈论 doProcessing 中的 w:
·因为 w 被声明为 Widget 范例的引用,w 必需支持 Widget interface(接口)。我们可以在源代码中找到这个 interface(接口)(譬喻,Widget 的 .h 文件)以看清楚它是什么样子的,所以我们称其为一个 explicit interface(显式接口)——它在源代码中显式可见。
·因为 Widget 的一些 member functions(成员函数)是虚拟的,w 对这些函数的挪用就表示为 runtime polymorphism(执行期多态):被挪用的特定函数在执行期基于 w 的 dynamic type(动态范例)来确定(拜见《C++箴言:毫不重界说担任的非虚拟函数》)。
templates(模板)和 generic programming(泛型编程)的世界是基础差异的。在谁人世界,explicit interfaces(显式接口)和 runtime polymorphism(执行期多态)继承存在,可是它们不那么重要了。作为替代,把 implicit interfaces(隐式接口)和 compile-time polymorphism(编译期多态)推到了前面。为了相识这是奈何一种环境,看一下当我们把 doProcessing 从一个 function(函数)转为一个 function template(函数模板)时会产生什么:
#p#副标题#e#
template<typename T>
void doProcessing(T& w)
{
if (w.size() > 10 && w != someNastyWidget) {
T temp(w);
temp.normalize();
temp.swap(w);
}
}
此刻我们可以如何谈论 doProcessing 中的 w 呢?
·w 必需支持的 interface(接口)是通过 template(模板)中在 w 身上所执行的操纵确定的。在本例中,它显现为 w 的 type (T) 必需支持 size,normalize 和 swap member functions(成员函数);copy construction(拷贝结构函数)(用于建设 temp);以及对不便是的较量(用于和 someNastyWidget 之间的较量)。我们将在今后看到这并不很准确,可是对付此刻来说它已经足够正确了。重要的是这一系列必需有效地适合于模板编译的表达式是 T 必需支持的 implicit interface(隐式接口)。
·对诸如 operator> 和 operator!= 这样的包括 w 的函数的挪用大概陪伴 instantiating templates(实例化模板)以使这些挪用乐成。这样的 instantiation(实例化)产生在编译期间。因为用差异的 template parameters(模板参数)实例化 function templates(函数模板)导致差异的函数被挪用,因此以 compile-time polymorphism(编译期多态)著称。
纵然你从没有利用过模板,你也应该熟悉 runtime(运行期)和 compile-time polymorphism(编译期多态)之间的区别,因为它雷同于确定一系列重载函数中哪一个应该被挪用的进程(这个产生在编译期)和 virtual function(虚拟函数)挪用的 dynamic binding(动态绑定)(这个产生在运行期)之间的区别。explicit(显式)和 implicit interfaces(隐式接口)之间的区别是与 template(模板)有关的新内容,需要对他举办近间隔的考查。
一个 explicit interface(显式接口)由 function signatures(函数识别特征)构成,也就是说,函数名,参数范例,返回值,等等。譬喻,Widget class(类)的 public interface(显式接口),
class Widget {
public:
Widget();
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other);
};
由一个 constructor(结构函数),一个 destructor(析构函数),以及函数 size,normalize 和 swap 构成,再加上 parameter types(参数范例),return types(返回范例)和这些函数的 constnesses(常量性)。(它也包罗 compiler-generated(编译器生成)的 copy constructor(拷贝结构函数)和 copy assignment operator(拷贝赋值运算符)——拜见《C++箴言:相识C++偷偷加上和挪用了什么》)它还大概包括 typedefs,尚有,假如你胆大包天敢于违背让 data members(数据成员)private(私有)的发起,纵然在这种环境下,这些 data members(数据成员)也不是。
#p#分页标题#e#
一个 implicit interface(隐式接口)有很大差异。它不是基于 function signatures(函数识别特征)的。它是由 valid expressions(正当表达式)构成的。再看一下在 doProcessing template 开始处的条件:
template<typename T>
void doProcessing(T& w)
{
if (w.size() > 10 && w != someNastyWidget) {
...
对付 T(w 的范例)的 implicit interface(隐式接口)看起来有如下这些约束:
·它必需提供一个名为 size 的返回一个正数值的 member function(成员函数)。
·它必需支持一个用于较量两个范例 T 的工具的 operator!= 函数。(这里,我们假定 someNastyWidget 的范例为 T。)
由于 operator overloading(运算符重载)的大概性,这两个约束都不必满意。是的,T 必需支持一个 size member function(成员函数),值得提及的是固然这个函数可以是从一个 base class(基类)担任来的。可是这个 member function(成员函数)不需要返回一个整数范例。它甚至不需要返回一个数值范例。对付这种环境,它甚至不需要返回一个界说了 operator> 的范例!它要做的全部就是返回范例 X 的一个 object(工具),有一个 operator> 可以用一个范例为 X 的 object(工具)和一个 int(因为 10 为 int 范例)来挪用。这个 operator> 不需要取得一个范例 X 的参数,因为它可以取得一个范例 Y 的参数,只要在范例 X 的 objects(工具)和范例 Y 的 objects(工具)之间有一个 implicit conversion(隐式转型)就可以了!
雷同地,T 支持 operator!= 也是没有须要的,因为假如 operator!= 取得一个范例 X 的 objects(工具)和一个范例 Y 的 objects(工具)是可接管的一样。只要 T 能转型为 X,而 someNastyWidget 的范例可以或许转型为 Y,对 operator!= 的挪用就是正当的。
(一个旁注:此处的阐明没有思量 operator&& 被重载的大概性,这会将上面的表达式的寄义从与转换到某些或许完全差异的对象。)
第一次思量 implicit interfaces(隐式接口)的时候,大大都人城市头疼,可是他们真的不需要阿司匹林。implicit interfaces(隐式接口)简朴地由一套 valid expressions(正当表达式)组成。这些表达式自身看起来大概很巨大,可是它们施加的约束凡是是简朴易懂的。譬喻,给出这个条件,
if (w.size() > 10 && w != someNastyWidget) ...
关于 functions size,operator>,operator&& 或 operator!= 上的约束很难说出更多的对象,可是要识别出整个表达式的约束长短常简朴的。一个 if 语句的条件部门必需是一个 boolean expression(布尔表达式),所以不管 "w.size() > 10 && w != someNastyWidget" 所发生的范例涉及到的准确范例,它必需与 bool 兼容。这就是 template(模板)doProcessing 施加于它的 type parameter(范例参数)T 之上的 implicit interface(隐式接口)的一部门。被 doProcessing 需要的 interface(接口)的其余部门是 copy constructor(拷贝结构函数),normalize 和 swap 的挪用对付范例 T 的 objects(工具)来说必需是正当的。
implicit interface(隐式接口)对 template(模板)的 parameters(参数)施加的影响正像 explicit interfaces(显式接口)对一个 class(类)的 objects(工具)施加的影响,并且这两者都在编译期间被查抄。正像你不能用与它的 class(类)提供的 explicit interface(显式接口)抵牾的要领利用 object(工具)(代码无法编译)一样,除非一个 object(工具)支持 template(模板)所需要的 implicit interface(隐式接口),不然你就不能在一个 template(模板)中试图利用这个 object(工具)(代码照旧无法编译)。
Things to Remember
·classes(类)和 templates(模板)都支持 interfaces(接口)和 polymorphism(多态)。
·对付 classes(类),interfaces(接口)是 explicit(显式)的并以 function signatures(函数识别特征)为中心的。polymorphism(多态性)通过 virtual functions(虚拟函数)呈此刻运行期。
·对付 template parameters(模板参数),interfaces(接口)是 implicit(隐式)的并基于 valid expressions(正当表达式)。polymorphism(多态性)通过 template instantiation(模板实例化)和 function overloading resolution(函数重载理会)呈此刻编译期。