Part 7テンプレートと汎用プログラミングTemplates and Generic Programming

5984 ワード

  • Rule 41:暗黙的インタフェースとコンパイル時のマルチステートunderstand implicit interfaces and compile-time polymorphismを理解する.

  • オブジェクト向けプログラミングは、常に明示的なインタフェース(explicit interfaces)とランタイムマルチステート(runtime polymorphism)で問題を解決します.
    覚えておいてください:(1)classesとTemplateはいずれもインタフェースとマルチステート(2)classにとってインタフェースが明示的で、関数署名を中心にして、以下の直接的な関数署名を定義します.
    Class Widget
    {
     public:
         Wigdet();
        virtual~ Widget();
        virtual std::size_t size() const;
        virtual void normalize();
        void swap(Widget& other);
    }。

    マルチステートはvirtual関数によって実行期間に発生します.(3)Templateパラメータの場合,インタフェースは暗黙的であり,定式化と有効表現である.マルチステートはTemplate具現化と関数リロード解析によってコンパイル期間に発生する.
  • Rule 42:typenameの二重の意味を理解するunderstand the two meanings of typename.1つの一般的な方法は、テンプレートクラスまたはテンプレートメソッドの定義で使用されます.もう1つのケースは、
  • template<typename C>
    void print2nd(const C& container)
    {
    if(container.size >=2)
        {
        C::const_iterator iter(container.begin());//     
        ++iter;
        int value = *iter;
        std::out<<value;
        }
    }

    この書き方のコンパイルは、コンパイラのデフォルトでは、ユーザーが指定しない限り、ネストされた依存名はタイプと見なされません.指定方法も固定されています.
    typename C::const_iterator iter(container.begin());
  • Rule 43:テンプレート化ベースクラス内の名称Know how to access names in templatized base classesを学習する.まず、次の例を参照してください.CompanyAとCompanyBは、異なる会社が処理するアルゴリズムによって、MsgSenderはメッセージ送信クラスであり、会社のメッセージ、明文形式、暗号化形式を送信することができます.
  • #include <iostream>
    using namespace std;
    
    class CompanyA{
    public:
        void sendCleartext(const std::string& msg){};
        void sendEncrypted(const std::string& msg){};
    };
    class CompanyB{
    public:
        void sendCleartext(const std::string& msg){};
        void sendEncrypted(const std::string& msg){};
    };
    
    class MsgInfo{};
    
    template<typename Company>
    class MsgSender{
    public:
    
        void sendClear(const MsgInfo& info)
        {
        std::string msg;
        //  ,  info    
        Company c;
        c.sendCleartext(msg);
        }
        void sendSecret(const MsgInfo& info)
        {
            std::string msg;
            //  ,  info    
            Company c;
            c.sendEncrypted(msg);
        }
    
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        MsgSender<CompanyA> ca;
        ca.sendClear(MsgInfo());
        getchar();
        return 0;
    }

    以上のコードは正常にコンパイル実行できます.次に,メッセージ送信時にログ記録の付加機能を追加する必要があると仮定し,以下に示すようにMsgSenderを継承する.
    template<typename Company>
    class LoggingMsgSender:public MsgSender<Company>{
    public:
    
        void sendClearMsg(const MsgInfo& info)
        {
            // “   ”     log
    
            //  base  
            sendClear(info);
    
            // “   ”     log;
        }
        void sendSecretMsg(const MsgInfo& info)
        {
            // “   ”     log
    
            //  base  
            sendSecret(info);
    
            // “   ”     log;
        }
    
    };

    Effective C++は、上記のコードが特定の厳格なコンパイラでコンパイル中にエラーが発生したことを示し、フラグ「sendClear」と「sendSecret」が見つからないことを示す.MsgSenderから継承されているため、この2つの方法自体が存在するはずです.本人はVS 2010 IDEで上記のコードを作成し、正常に動作します.保険のため,著者らは3つの解決策を提示した:1つ目はbase class関数呼び出し動作の前にthis->を加えることである.this->sendClear(info);の2つ目はusing宣言式を使用して、次のようにします:using Msgsender<Company>::sendClear//はコンパイラにsendClearがbase class内にあると仮定してください.この方法は、base classの役割ドメインに入らないコンパイラがあるので、usingでそうしてくださいと伝えます.3つ目の方法は、呼び出された関数がbase class内にあることを理解することである.Msgsender<Company>::sendClear(info)//OKは、sendClearが継承されると仮定するが、virtual関数が呼び出されると、上記の宣言メソッドが「virtualバインド動作」を閉じるため、この方法は満足できないことが多い.