41:了解隐式接口和编译期多态

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

例如:

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,可以这样说:

1.由于w的类型被声明为Widget,所以w必须支持Widget接口。

我们可以在源码中找出这个接口,看看它是什么样子,所以称此为一个显式接口,也就是它在源码中明确可见。

2.由于Widget的某些成员函数是virtual,w对那些函数的调用将表现出运行期多态,也就是说,将于运行期根据w的动态类型决定究竟调用哪一个函数。

在template及泛型编程的世界中,显式接口和运行期多态仍然存在,但重要性降低。反倒是隐式接口和编译期多态移到前面了。

看下面的这段代码:

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

现在,对于doProcessing内的w,可以这样说:

1.w必须支持哪一种接口,由template中执行于w身上的操作来决定。

在本例中w的类型T好像必须支持size,normalize和swap成员函数等。

2.凡涉及w的任何函数调用,例如oprator >和operator !=,有可能造成template具现化,使这些调用得以成功。这样的具象行为发生在编译期。

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

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

现在来看显式接口与隐式接口之间的差异。

通常显式接口由函数的签名式(也就是函数名称、参数类型、返回类型)构成。

例如:

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

隐式接口就完全不同。它并不基于函数签名式,而是由有效表达式组成。

再次看看doProcessing template一开始的条件:

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

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

2.它必须支持一个operator !=函数,用来比较两个T对象。这里假设someNastyWidget的类型为T。

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

例如以下表达式:

if (w.size() > 10 && w != someNastyWidget)

无论上述表达式导致什么,它都必须与bool兼容。这是template doProcessing加诸于其类型参数T的隐式接口的一部分。

doProcessing要求的其他隐式接口:copy构造函数、normalize和swap也都必须对T型对象有效。

加诸于template身上的隐式接口,就像加诸于class对象身上的显式接口一样真实,而且两者都在编译期完成检查。

就像你无法以一种“与class提供的显式接口矛盾”的方式来使用对象(代码将通不过编译),你也无法在template中使用“不支持template所要求的隐式接口”的对象(代码一样通不过编译)。

总结

1.class和template都支持接口和多态。

2.对class而言接口是显式的,以函数签名为中心。多态则是通过virtual函数发生于运行期。

3.对template参数而言,接口是隐式的,奠基于有效表达式。多态则是通过template具现化和函数重载解析发生于编译期。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值