Effective C++ —— 模板与泛型编程(七)

论坛 期权论坛     
选择匿名的用户   2021-5-30 01:40   83   0
<div class="blogpost-body" id="cnblogs_post_body">
<p><span style="font-size:16px;"><span style="font-size:15px;">  C&#43;&#43; templates的最初发展动机很直接:让我们得以建立“类型安全”的容器如vector,list和map。然而当愈多人用上templates,他们发现templates有能力完成愈多可能的变化。容器当然很好,但<span style="color:#ff0000;">泛型编程</span>——写出的代码和其所处理的对象类型彼此独立——更好。<span style="color:#ff0000;">STL算法如for_each, find 和 merge 就是这一类编程的成果</span>。最终人们发现,C&#43;&#43; template机制自身是一部完整的图灵机:它可以被用来计算任何可计算的值。于是导出了<span style="color:#ff0000;">模板元编程</span>,创造出“在C&#43;&#43;编译器内执行并于编译完成时停止执行”的程序。容器反倒只成为C&#43;&#43; template 上的一小部分。然而,尽管template 的应用如此宽广,有一组核心观念一直支撑着所有基于template的编程。那些观念便是本章焦点。</span></span></p>
<p><span style="font-size:16px;"><strong>条款41 : 了解隐式接口和编译期多态</strong></span></p>
<div class="entry">
  <div>
   <p><span style="font-size:15px;">  <span style="color:#000000;">面向对象编程世界</span>总是以显式接口和运行期动态解决问题。如下代码所示:</span></p>
   <div class="cnblogs_code">
    <pre class="blockcode"><span style="color:#0000ff;">class</span><span style="color:#000000;"> Widget
{
    </span><span style="color:#0000ff;">public</span><span style="color:#000000;">:
        Widget();
        </span><span style="color:#0000ff;">virtual</span> ~<span style="color:#000000;">Widget();
        </span><span style="color:#0000ff;">virtual</span> std::size_t size() <span style="color:#0000ff;">const</span><span style="color:#000000;">;
        </span><span style="color:#0000ff;">virtual</span> <span style="color:#0000ff;">void</span><span style="color:#000000;"> normalize();
        </span><span style="color:#0000ff;">void</span> swap(Widget&amp; other);     <span style="color:#008000;">//</span><span style="color:#008000;"> 条款25</span>
<span style="color:#000000;">        .....
};

</span><span style="color:#0000ff;">void</span> doProcessing(Widget&amp;<span style="color:#000000;"> w)
{
    </span><span style="color:#0000ff;">if</span> (w.size() &gt; <span style="color:#800080;">10</span> &amp;&amp; w !&#61;<span style="color:#000000;"> someNastyWidget)
    {
        Widget temp(w);
        temp.normalize();
        temp.swap(w);
    }
}</span></pre>
   </div>
   <p><span style="font-size:15px;">  (1)由于w的类型被声明为Widget,所以w必须支持Widget接口。我们可以在源码中找出这个接口,看看它是什么样子,所以我们称为一个显式接口,也就是它在源码中明确可见。</span></p>
   <p><span style="font-size:15px;">  (2)由于Widget的某些成员函数是virtual,w对那些函数的调用将表现出运行期多态,也就是说将于运行期根据w的动态类型(条款37)决定究竟调用哪一个函数。</span></p>
   <p><span style="font-size:15px;">  Templates及泛型编程的世界,与面向对象有根本不同。在此世界中显式接口和运行期多态仍然存在,但重要性降低。反倒是隐式接口和编译器多态更显重要了。如下:</span></p>
   <div class="cnblogs_code">
    <pre class="blockcode"><span style="color:#ff0000;">template&lt;typename T&gt;</span>
<span style="color:#0000ff;">void</span> doProcessing(T&amp;<span style="color:#000000;"> w)
{
    </span><span style="color:#0000ff;">if</span> (w.size() &gt; <span style="color:#800080;">10</span> &amp;&amp; w !&#61;<span style="color:#000000;"> someNastyWidget)
    {
        Widget temp(w);
        temp.normalize();
        temp.swap(w);
    }
}</span></pre>
   </div>
   <p><span style="font-size:15px;">  (1)w 必须支持哪一种接口,系由template中执行于w身上的操作来决定。本例看来w的类型T好像必须支持size,normalize和swap成员函数,copying函数(用来建立temp),不等比较(用来比较someNasty-Widget)等等。<span style="color:#ff0000;">这一组表达式(对此template而言必须有效编译)便是T必须支持的一组隐式接口</span>。</span></p>
   <p><span style="font-size:15px;">  (2)凡涉及w的任何函数调用,例如operator&gt;和operator!&#61;,有可能造成template具现化,使这些调用得以成功。这样的具现行为发生在编译期。“<span style="color:#ff0000;">以不同的template参数具现化function templates(函数模板)”会导致调用不同的函数</span>,这个便是所谓的编译期多态。(“哪一个函数应该被调用”——发生在编译期; “哪一个virtual函数该被绑定”——发生在运行期)。</span></p>
   <p><span style="font-size:15px;">  通常,显式接口由函数签名式(也就是函数名称、参数
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP