标签:参数 color 对象 roc ... 文件中 har 头文件 成功
面向对象编程的世界围绕着显式接口和运行时多态。举个例子,考虑下面的类(无意义的类),
1 class Widget { 2 public: 3 Widget(); 4 virtual ~Widget(); 5 6 virtual std::size_t size() const; 7 virtual void normalize(); 8 9 void swap(Widget& other); // see Item 25 10 11 ... 12 13 };
考虑下面的函数(同样没有意义),
1 void doProcessing(Widget& w) 2 3 { 4 5 if (w.size() > 10 && w != someNastyWidget) { 6 7 Widget temp(w); 8 9 temp.normalize(); 10 11 temp.swap(w); 12 13 } 14 15 }
对于doProcessing中的w,我们可以这样说:
模板(template)和泛型编程(generic programming)的世界从根本上发生了变化。在这个世界中,显式接口和运行时多态继续存在,但是它们不再像以前那么重要。相反,隐式接口和编译时多态被挪到了前台。为了了解这是什么样子的,我们将doProcessing从函数转换为一个函数模板,看看会发生什么:
1 template<typename T> 2 3 void doProcessing(T& w) 4 5 { 6 7 if (w.size() > 10 && w != someNastyWidget) { 8 9 T temp(w); 10 11 temp.normalize(); 12 13 temp.swap(w); 14 15 } 16 17 }
现在我们能对doProcessing中的w说些什么呢?
即使你永远不使用模板,你也应该熟悉运行时多态和编译期多态的区别,因为这同编译期决定调用哪个重载函数以及运行期决定绑定哪个虚函数是类似的。隐式和显式接口的区别对于模板来说是新的概念,然而,一个显式的接口由函数签名组成,也即是函数名字,参数类型,返回值类型等等。Widget类的公共接口,例如:
1 class Widget { 2 public: 3 Widget(); 4 virtual ~Widget(); 5 virtual std::size_t size() const; 6 virtual void normalize(); 7 void swap(Widget& other); 8 };
由一个构造函数,一个析构函数,和函数size,normalize和swap以及参数类型,返回值类型和这些函数的常量性组成。(同样包含编译器生成的拷贝构造函数和拷贝赋值运算符——看Item 5)。它同样可以包含typedef和数据成员,如果你够大胆违反Item22的建议的话(将数据成员声明为private)。虽然在这个例子中没有这么做。
一个隐式的接口会有很大的不同。它不是基于函数签名。而是由有效表达式组成。再看一下doProcessing模板开始部分的条件表达式:
1 template<typename T> 2 void doProcessing(T& w) 3 { 4 if (w.size() > 10 && w != someNastyWidget) { 5 ...
T(w的类型)的隐式接口看上去会有如下限制:
多亏了操作符重载,上面的两个限制都不需要满足。T必须支持一个size成员函数,值得提及的是这个函数可能继承自一个基类。但是这个成员函数没有必要返回一个整型值。甚至不需要返回一个数字类型值。如果这么说的话,它甚至不需要返回operator>定义中所需要的值。他需要的是返回一个类型X的对象,于是可以在一个类型X对象和int(因为10是int型的)型对象上调用operator>。但是Operator>没有必要带一个类型X的参数,因为它也可以带一个类型Y的参数,只要Y可以隐式的转成X就可以了。
类似的,T也没有必要支持operator!=,因为operator!=带一个类型X的参数和一个类型Y的参数也能接受。只要T能转成X并且someNastyWidget的类型可以转换成Y,那么函数调用就是有效的。
(说句题外话,这个分析没有考虑将operator&&进行重载的可能性,这样就将上面的表达式的意思从一个连接词转换成了其它的意义迥然的东西。)
大多数人当第一次开始考虑这种隐式转换就头疼,你不需要吃阿司匹林。隐式接口只是简单的由一些有效表达式组成。表达式本身看起来复杂,但是加在上面的限制一般来说是简单直接的。例如,考虑下面的条件表达式,
1 if (w.size() > 10 && w != someNastyWidget) ...
很难说要对函数size,operator>,operator&&或者operator!=做什么限制,但是很容易辨认出需要对整个表达式做出的限制。If声明的条件部分必须是一个boolean表达式,所以不管涉及到什么类型,也不管w.size() > 10 && w != someNastyWidget产生什么,它必须同bool是兼容的。这是模板doProcessing强加在类型参数T上的隐式接口的一部分。剩下的doProcessing所需要的接口就是对拷贝构造函数的调用,还有swap对于类型T来说必须是有效的。
强加在模板参数上的隐式接口同强加在类对象上的显示接口一样真实,两者都是在编译阶段检查。你不能同一个类提供的显示接口相矛盾的方式使用一个类对象(不会编译通过),你也不能随便在一个模板中尝试使用一个对象,除非这个对象支持模板需要的隐式转换(否则也不能通过编译)
读书笔记 effective c++ Item 41 理解隐式接口和编译期多态
标签:参数 color 对象 roc ... 文件中 har 头文件 成功
原文地址:http://www.cnblogs.com/harlanc/p/6649086.html