您的位置:首页 > 编程语言 > C语言/C++

《Effective C++》学习笔记——条款41

2016-03-07 00:14 274 查看

七、模板与泛型编程

C++ template的最初动机 —— 让我们得以建立“类型安全”的容器,如 vector,list 和 map。

而且 泛型编程写出的代码和其所处理的对象类型彼此独立。

C++ template机制自身是一部完整的图灵机:它可以被用来计算任何可计算的值。于是,导出了模板元编程,创造出“在C++编译器内执行并于编译完成时停止执行”的程序。

条款41、了解隐式接口和编译期多态

1. 显示接口 及 运行期多态

面向对象的世界总是以显示接口和运行期多态解决问题。

class Widget {
public:
Widget();
virtual ~Widget();
virtual std::size_t size() const;
virtual void normalize();
void swap(Widget& other);
...
};

void doProcessing(Widget& w)
{
if( w.size() > 10 && w != someNastyWidget )  {
Widget temp(w);
temp.normalize();
temp.swap(w);
}
}


我们可以说doProcessing的w:

由于w的类型被声明为Widget,所以w必须支持Widget接口,我们可以在源码中找出接口(在.h文件中),所以它在源码中明确可见。

由于Widget的某些成员函数是virtual的,所以将在运行期根据w的动态类型决定调用哪个函数,即 w对那些函数的调用表现出运行期多态。

2. 隐式接口 及 编译器多态

将上述例子中的 doProcessing函数 转变为 函数模板

template<typename T>
void doProcessing(T& w)
{
if( w.size() > 10 && w != someNastyWidget )  {
T temp(w);
temp.normalize();
temp.swap(w);
}
}


再来说说doProcessing里的w

w必须支持哪一种接口,由template中执行于w身上的操作来决定。本例中,w的类型T必须支持size,normalize 和 swap成员函数、copy构造函数、不等比较等。

只要涉及w的任何函数调用,比如 operator > 与 !=,有可能造成template具现化,这样的具现行为发生在编译器。

“以不同的template参数具现化function templates”会导致调用不同的函数,这便是所谓的编译期多态。

3. 编译期多态 与 运行期多态 的 差异 and 显式接口 与 隐式接口 的 差异

编译期多态 与 运行期多态 的差异类似于 哪一个重载函数应该被调用(发生在编译期) 与 哪一个virtual函数该被绑定(发生在运行期)。

显式接口 与 隐式接口 的差异可以通过例子来讲述:

通常 显式接口由函数的签名式(函数名称、参数类型、返回类型)构成,比如Widget类的 构造函数、析构函数、size、normalize、swap函数 及其 参数类型、返回类型、常量性,还有 编译器产生的 copy构造函数 与 copy assignment操作符。

此外,也可以包括 typedefs

class Widget {
public:
Widget();
virtual ~Widget();
virtual 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 )  {
...
}
}


T的隐式接口有这些约束

必须提供一个名为size的成员函数,该函数返回一个整数值。

必须支持一个 operator != 函数,用来比较两个T对象(此处假设 someNastyWidget类型为T)

隐式接口仅仅是由一组有效表达式构成,表达式自身可能看起来复杂,但它们要求的约束条件一般简单又明确。

在 template 参数身上的隐式接口,就像加在 class 对象身上的显式接口,两者都在编译期完成检查。

4. 请记住

class 和 template 都支持接口 和 多态

对 class 而言接口是 显示的(explicit),以函数签名为中心;多态则是通过 virtual函数 发生于 运行期

对 template 参数而言,接口是 隐式的(implicit),奠基于有效表达式;多态则是通过template具现化 和 函数重载解析 发生于编译期
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  学习笔记