面向对象编程总是以显示接口和运行期多态解决问题,考虑如下代码:
// 无意义的class
class Widget {
public:
Widget();
virtual ~Widget();
virtual void std::size_t size() const;
virtual void normalize();
void swap(Widget &other);
};
// 一个无意义的函数
void doProcessing (Widget &w) {
if (w.size() > 0 && w != someNastWidget) {
Widget temp(w);
temp.normalize();
temp.swap(w);
}
}
- 由于
w
的类型被声明为Widget
,所以w必须支持Widget
接口,这称为一个显示接口(因为我们可以找出Widget
的源代码) - 由于
Widget
有virtual
成员函数,w
对哪些函数的调用将表现出运行期多态
如果我们将doProcessing
从函数转为函数模板呢?:
template<typename T>
void doProcessing(T &w) {
if (w.size() > 10 && w != someNastyWidget) {
T temp(w);
temp.normalize();
temp.swap(w);
}
}
- 现在
w
必须支持一种接口,系由template
中执行于w
身上的操作来决定 - 凡涉及
w
的任何函数调用,例如operator>
和operator!=
,有可能造成template
的具现化(发生在编译期)
通常显式接口由函数的签式(也就是函数名称,参数类型,返回类型)构成,例如Widget class
:
class Widget {
public:
Widget();
virtual ~Widget();
virtual void std::size_t size() const;
virtual void normalize();
void swap(Widget &other);
};
隐式接口并不基于函数签名式,而是有效表达式:
template<typename T>
void doProcessing(T &w) {
if (w.size() > 10 && w != someNastyWidget) {
// ...
}
}
classes
和templates
都支持接口和多态- 对
classes
而言接口是显式的,以函数签名为中心,多态则是通过virtual
函数发生于运行期 - 对
template
参数而言,接口是隐式的,基于有效表达式;多态是通过template
具现化和函数重载解析发生于编译期