Effective C++読書ノートItem 23非メンバー非友元関数はメンバー関数より優れている

2519 ワード

実は簡単に言えば、メンバー関数はクラスで定義された関数であり、メンバー関数ではなく普通の関数であり、クラスで定義された関数ではないか.非メンバー関数は典型的には友元関数である.以下に、他のいくつかの違いと理解を貼ります.
メンバー関数はクラス定義の一部であり、特定のオブジェクトによって呼び出されます.メンバー関数は、メンバーオペレータを使用することなく、呼び出しオブジェクトのメンバーに暗黙的にアクセスできます.メタ関数はクラスの構成部分ではないので、直接関数呼び出しと呼ばれます.友元関数はクラスメンバーに暗黙的にアクセスすることはできません.パラメータとして渡されるオブジェクトにメンバーオペレータを使用する必要があります.
クラスの実装では、メンバー関数と非メンバー関数の選択に直面することが多い.たとえば、ブラウザクラス:
class WebBrowser{
public:
  void clearCache();
  void clearCookies();
  void clearHistory();
};
clearEverything()を実現するには2つの方法があります.
class WebBrowser{
public:
  void clearEverything(){
    clearCache();
    clearCookies();
    clearHistory();
  }
}
//          :
void clearEverything(WebBrowser& wb){
  wb.clearCache();
  wb.clearCookies();
  wb.clearHistory();
}

どちらがいいですか.オブジェクト向けの原則は、データとデータ上の操作を結びつけるべきであり、前者がより良いことを指摘している.これはオブジェクト向けの誤解であり,オブジェクト向け設計の真髄はパッケージにあり,データはできるだけカプセル化されるべきである.メンバー関数に比べて、非メンバー関数は、より良いパッケージ、パッケージの柔軟性(コンパイル依存性の低減)、および機能拡張性を提供します.
パッケージ性パッケージとは、外部に隠すという意味です.データがよりよくカプセル化されればするほど、少ないものほどそれを見ることができ、私たちはより大きな柔軟性を持ってそれを変えることができます.これはパッケージがもたらす最大のメリットです.何かを変える柔軟性を与え、このような変更は限られたお客様に影響を与えるだけです.
粗粒度の推定として、データのカプセル化性は、データにアクセス可能な関数の数に反比例する.これらの関数には、メンバー関数、友元関数、および友元クラスの関数が含まれます.したがって、非メンバー非友元関数はメンバー関数よりも良いパッケージを提供し、clearEverything()の第2の実装を選択する必要があります.
Item 22は、データ・メンバーがプライベートでない場合、無限数の関数がアクセスできると述べています.
ここには2つの注意点があります.
友元関数はメンバー関数と同じです.友元関数はプライベートデータメンバーにもアクセスできるため、パッケージに同じ影響を及ぼすメンバー関数です.非メンバー関数は、他のクラスのメンバー関数ではないことを意味しません.特にJava、C#などの言語では、関数をクラスに定義する必要があります.静的メンバー関数も良い選択です.静的関数はオブジェクトメンバーにアクセスできないため、オブジェクトのカプセル化には影響しません.拡張性はC++で、これらの非メンバー関数を同じネーミングスペースで定義できます.しかし、問題はまた発生しました.これらのネーミングスペースの関数はクラスになく、すべてのソースファイルに伝播します.お客様は、いくつかのツール関数を使用するために、このような膨大なネーミングスペースにコンパイル依存することを望んでいません.したがって、異なるカテゴリのツール関数を異なるヘッダファイルに配置することができ、お客様はその機能の一部を選択することができます.
// file: webbrowser.h
namespace WebBrowserStuff{
  class WebBrowser{};
}
 
// file: webbrowser-bookmarks.h
namespace WebBrowserStuff{
  ...
}
 
// file: webbrowser-cookies.h
namespace WebBrowserStuff{
  ...
}

これもC++標準ライブラリの組織方式で、stdネーミングスペースの下のすべてのものは異なるヘッダファイルに分けられています:,,など.これにより、クライアントコードは、導入された機能の一部にのみコンパイル依存性を生じます.これを行うには、クラス全体として1つのファイルで定義する必要があるため、これらのツール関数は非メンバー関数でなければなりません.
同じネーミングスペースの異なるヘッダファイルの組織方法は、お客様の拡張ツール関数にも可能です.お客様は、同じネーミングスペースで独自のツール関数を定義できます.これらの関数は、既存のツール関数と天然に統合されます.これも、クラスの定義が顧客拡張に対して閉じられているため、メンバー関数ではできない特性です.サブクラスでもカプセル化された(プライベート)メンバーデータにアクセスできず、ベースクラスとして使用されないクラスもあります(Item 7:マルチステートベースクラスの構造関数を虚関数として宣言するを参照).