Effective C++学習ノートの第4章(4)

3396 ワード

chapter 4設計と宣言
item 23:non-member、non-friend関数でmember関数を置き換えるよりも1)ここにwebブラウザに関するクラスがあり、一連の明確な操作があり、最後にすべてのものをクリアするために関数を書く必要があります.つまり、すべての明確な操作を呼び出す必要があります.コードは次のとおりです.
class WebBrowser {
public:
  ...
  void clearCache();
  void clearHistory();
  void removeCookies();
 ...
};
//  1:              
class WebBrowser {
public:
  ...
  void clearEverything(); // calls clearCache, clearHistory,and removeCookies
  ...
};
//  2:                
void clearBrowser(WebBrowser& wb)
{
  wb.clearCache();
  wb.clearHistory();
  wb.removeCookies();
}

もちろん、上の2つの実現方法は、どちらがいいですか.オブジェクト向けの原理から言えば、パッケージが要求されるのではないでしょうか.それはきっと最初の方法がもっといいに違いない.そう思うと、それはオブジェクト向けのメカニズムに対する誤解です.これを2つの側面から論じる.まず、カプセル化という言葉の意味は、何かを隠すことであり、一つのものをカプセル化すればするほど、少ない人ほど見ることができるはずだ.少ない人が見れば見るほど、メンテナンスが便利になります.修正が必要な場合は、見えるものだけを修正すればいいからです.次に、オブジェクトのメンバー変数を考慮します.item 22では、メンバー変数をできるだけprivateと書くと、後で変更しやすくなりますが、privateメンバー変数を変更する作業量は、privateメンバー変数にアクセスできる関数と友元関数の数に依存します.したがって、メンバー関数と非メンバー関数を比較すると、非メンバー関数はより良いパッケージ性を提供します.2)この点で注意すべきことは二つある.まず、メタ関数のアクセス権はメンバー関数と同様にprivate変数にアクセスできます.メンバー関数と非メンバー関数の間で選択するわけではありません(もちろんカプセル化は唯一の考慮ではなく、item 24は暗黙的な変換が必要な場合、メンバー関数と非メンバー関数の間で選択する必要があると説明します)ではなく、メンバー関数と非メンバー非友元関数の間で選択する必要があります.次に、カプセル化の観点から、1つの関数は1つのクラスのメンバー関数にはならず、別のクラスの成にはならないことを意味しません.メンバー関数.WebBrowserの一部でない限り、WebBrowserメンバー変数のパッケージ性を破壊することなく、clearBrowserを別の実用クラスの静的メンバー関数として使用することができます.3)C++では,あるクラスの非メンバー関数とこのクラスを同じnamespaceに入れるのがより自然な方法である.もちろんこれは自然に見えるだけではありません.namespaceは複数のソースファイルにまたがることができますが、classはできません.これは重要で、clearBrowserのようなconvenince functionは、メンバー関数でも友元関数でもないし、特別なアクセス権もないし、「ユーザーが他の方法で得る」機能も提供できない.例えばclearBrowserが存在しない場合、ユーザーは自分で一連のクリア関数を呼び出すしかない.
namespace WebBrowserStuff {
 class WebBrowser { ... };
 void clearBrowser(WebBrowser& wb);
 ...
}

4)もちろん、1つのクラスには、WebBrowserのような多くのconvenince functionがある可能性があります.ブックマークに関連するものもあれば、印刷に関連するものもあれば、クッキー管理に関連するものもあります.ユーザーがブックマークに関するconvenince functionだけに関心を持っているのに、cookie管理に関するconvenince functionとコンパイル依存関係があるという理由はありません.彼らを分離する最後の方法は、異なる関連convenience functionを異なる同じファイルに置くことです.例えば、次のようにします.
// header "webbrowser.h" — header for class WebBrowser itself
// as well as "core" WebBrowser-related functionality
namespace WebBrowserStuff {
   class WebBrowser { ... };
   ...  // "core" related functionality, e.g.non-member functions almost all clients need
}
// header "webbrowserbookmarks.h"
namespace WebBrowserStuff {
  ...  // bookmark-related convenience functions
} 
// header "webbrowsercookies.h"
namespace WebBrowserStuff {
  ... // cookie-related convenience functions
} 

これがC++標準ライブラリの組織方法であることに気づきました.例えばnamespace stdといえば、中には数十個のヘッダファイルがあり、各ヘッダファイルにはいくつかの機能が実現されており、どちらを使うか、includeどちらを使えばいいのです.これにより、お客様は、使用しているシステムのほんの一部に対してのみコンパイル依存性を形成することができます.(item 31ではコンパイル依存性を低減する他の方法が議論されている).このようにclassを切り分けることは不可能である.classは全体として定義しなければならないからである.5)すべてのconvenince functionを同じnamespaceであるが異なるヘッダファイルに配置することは、ユーザーがconvenince functionを容易に拡張できることを意味する.例えばダウンロードに関連するconvenince functionは、WebBrowserStuffのnamespaceにヘッダファイルを新規作成し、追加するconvenince functionを宣言するだけです.これらの関数は使用できます.これはclassでは不可能です.クラスはお客様にとって拡張できないため、もちろん新しいクラスを派生することができますが、派生クラスはベースクラスのprivate変数にアクセスできません.また,各クラスがベースクラスとして設計されているわけではない.6)したがってnon-member,non-friend関数を用いると,パッケージング性(encapsulation),パッケージング弾性(packaging flexibility),スキル拡張性(functional extensibility)を増加させることができる.