Part 7テンプレートと汎用プログラミングTemplates and Generic Programming
5984 ワード
オブジェクト向けプログラミングは、常に明示的なインタフェース(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具現化と関数リロード解析によってコンパイル期間に発生する.
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());
#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バインド動作」を閉じるため、この方法は満足できないことが多い.