条款41:了解隐式接口和编译期多态
1.1 接口
- 一个显式接口通常由函数签名,即函数名,参数类型、返回类型等。
- 隐式接口则完全不同。它不基于函数签名。相反,它由有效的表达式(例如上面例子的w.size()只要能和int比较就可,不一定非要返回int)组成。
1.2 面向对象编程
面向对象编程的世界里,充斥着显式接口和运行时多态性。
class Widget {
public:
Widget();
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other);
...
}
//w被声明为Widget类型,所以w必须支持Widget接口。通过查看源码就能确定,可称之为显式接口
//一些Widget的成员函数是虚的,要调用的具体函数将在运行时根据w的动态类型确定
void doProcessing(Widget& w)
{
if (w.size() > 10 && w != someNastyWidget) {
Widget temp(w);
temp.normalize();
temp.swap(w);
}
}
1.3 模板和泛型编程
模板和泛型编程的世界是完全不同的。显式接口和运行时多态仍然存在,但它们不那么重要了。相反,隐式接口和编译时多态性被推到了前台。
template<typename T>
//w必须支持的接口由模板中对w执行的操作决定(隐式的)
//因为使用不同的模板参数实例化函数模板会导致调用不同的函数,这被称为编译时多态性
void doProcessing(T& w)
{
if (w.size() > 10 && w != someNastyWidget) {
T temp(w);
temp.normalize();
temp.swap(w);
}
}
1.4 总结
- 类和模板都支持接口和多态性。
- 对于类来说,接口是显式的,并且以函数签名为中心。多态性通过虚函数在运行时发生。
- 对于模板参数,接口是隐式的,并且基于有效的表达式。多态性在编译过程中通过模板实例化和函数重载解析发生于编译期。