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




七、模板与泛型编程

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的隐式接口有这些约束

    1. 必须提供一个名为size的成员函数,该函数返回一个整数值。
    2. 必须支持一个 operator != 函数,用来比较两个T对象(此处假设 someNastyWidget类型为T)

隐式接口仅仅是由一组有效表达式构成,表达式自身可能看起来复杂,但它们要求的约束条件一般简单又明确。
在 template 参数身上的隐式接口,就像加在 class 对象身上的显式接口,两者都在编译期完成检查。


4. 请记住
  • class 和 template 都支持接口 和 多态
  • 对 class 而言接口是 显示的(explicit),以函数签名为中心;多态则是通过 virtual函数 发生于 运行期
  • 对 template 参数而言,接口是 隐式的(implicit),奠基于有效表达式;多态则是通过template具现化 和 函数重载解析 发生于编译期




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值