2011-10-19 8 views
15

マイヤーは、特定のシナリオでは、メンバー以外の非友人機能がメンバー機能よりも優れていることを実証C++で説明しています。メンバ関数以外の非フレンド関数をいつ使うべきですか?

例:

// Web browser allows to clear something 
class WebBrowser { 
public: 
    ... 
    void clearCache(); 
    void clearHistory(); 
    void removeCookies(); 
    ... 
}; 

多くのユーザーはそうWebBrowserもちょうどそれを行うための機能を提供するかもしれない、一緒にすべてのこれらのアクションを実行することになるでしょう:

class WebBrowser { 
public: 
    ... 
    void clearEverything(); // calls clearCache, clearHistory, removeCookies 
    ... 
}; 

他の方法を定義することですメンバー以外の非友人機能。 「それは、クラスのプライベートな部分にアクセスできる機能の数を増加させない。」ので、より良好にカプセル化につながる

void clearBrowser(WebBrowser& wb) 
{ 
    wb.clearCache(); 
    wb.clearHistory(); 
    wb.removeCookies(); 
} 

非メンバ関数が良いです。彼らはWebBrowserクライアントがすでにいくつかの他の方法で得ることができませんでした任意の機能を提供することはできませんのでclearBrowserよう

機能便利な機能です。たとえば、clearBrowserが存在しない場合、クライアントはclearCacheclearHistory、およびremoveCookiesを呼び出すことができます。

私には、の便利な機能の例が妥当です。しかし、メンバー以外のバージョンが優れている場合、便利機能以外の例はありますか?

さらに一般的には、どのような場合にどのような規則を使用しますか

+4

私は、そのトピックに実際の客観的なルールよりも多くの宗教があると思います。 – PlasmaHH

+1

任意の種類のアルゴリズムは、より広い範囲のオブジェクトに対して再利用できるので、メンバーではなく自由であるという利点があります。その一例は、新しい標準に追加された無料の 'begin()'/'end()'関数です(静的な配列とコンテナを反復することができます)。 –

+3

@PlasmaHH:それはもっと宗教に似ているとは思わない。一部の機能を非会員かつ非友人にするための論理的根拠はかなり合理的です。 – Nawaz

答えて

20

さらに一般的には、どのような場合にどのような規則が使用されますか?ここで

スコット・マイヤーのルールは、(source)あるものです:

スコットは非会員非フレンド関数は、クラスのカプセル化 を向上させること を提唱印刷で興味深い記事があります。彼は、関数fが置か取得する場所 を決定するために、次のアルゴリズムを使用します。

if (f needs to be virtual) 
    make f a member function of C; 
else if (f is operator>> or operator<<) 
{ 
    make f a non-member function; 
    if (f needs access to non-public members of C) 
     make f a friend of C; 
} 
else if (f needs type conversions on its left-most argument) 
{ 
    make f a non-member function; 
    if (f needs access to non-public members of C) 
     make f a friend of C; 
} 
else if (f can be implemented via C's public interface) 
    make f a non-member function; 
else 
    make f a member function of C; 

カプセル化の彼の定義は、プライベートデータ メンバーが変更されたときに影響を受ける機能の数 を必要とします。

これはかなり多くのことをまとめていますが、私の意見ではかなり合理的です。

0

非メンバ関数は、ライブラリの開発者がいずれかの引数でクラス型でオーバーロードできるバイナリ演算子を書きたい場合によく使用されます。クラスのメンバにすると、 2番目の引数(最初は暗黙的にそのクラスのオブジェクトです)。おそらくvarious arithmetic operatorscomplexがこれの決定的な例です。

あなたが引用した例では、動機づけは別の種類のものです。ジョブを実行できる最小結合設計を使用してください。

これは、clearEverythingがメンバーになる可能性がある(そして、率直に言えば、そうである可能性が高い)一方で、技術的には必要ないので、メンバーにすることはできません。

  1. あなたはあなたのパブリックインターフェイス(あなたは1に同梱されて一度、あなたは「生活のためにそれに結婚し直す)にclearEverything方法を持っていることの責任を受け入れることはありません:これはあなたに二つのことを買います。
  2. クラスのメンバーにアクセスする機能の数が1つ少ないため、将来の変更は簡単に実行でき、バグが発生しにくくなります。

私は、この特定の例では、概念があまりにも遠すぎると感じており、そのような「無実の」機能について、私はそれをメンバーにすることに重点を置いています。しかし、そのコンセプトは健全であり、物事がそれほど単純ではない「現実の」シナリオでは、はるかに理にかなっています。

3

多くの場合、アプリケーション固有のクラスの外にユーティリティメソッドを構築することを選択します。

通常、アプリケーションは異なるコンテキストにあり、エンジンはその下で作業を行います。 Webブラウザの例を挙げると、3つの明確なメソッドはWebエンジンに属しています。これは、他の場所では実装が難しい機能ですが、ClearEverything()はアプリケーション固有の機能です。この場合、アプリケーションに小さなダイアログが表示され、ユーザーがより効率的に操作できるようにするには、すべてをクリアするボタンがあります。たぶんこれはあなたのWebブラウザエンジンを再利用している別のアプリケーションがやりたいことではないかもしれませんし、そのためにエンジンクラスでそれを持つことはちょっと混乱します。

もう1つの例は、数学ライブラリです。平均値や標準派生などの高度な機能を数学的なクラスの一部として実装することはしばしば理にかなっています。ただし、標準バージョンではない平均値を計算するアプリケーション固有の方法がある場合、それはおそらくクラス外であり、アプリケーション固有のユーティリティライブラリの一部である必要があります。

私は決して強硬なハードコーディングされたルールを使って何かを実装することはありませんでした。それはしばしばイデオロギーと原則の問題です。

M.

0

地域とカプセル化を維持しながら、クラスが「十分」な機能を提供することを可能にするには、考慮すべきいくつかのものです。

WebBrowserが多くの場所で再使用される場合、依存関係/クライアントは複数の便利機能を定義することがあります。これにより、クラス(WebBrowser)は軽量で管理しやすくなります。

逆は、WebBrowserがすべてのクライアントを満足させることになり、ちょうど変更するのが難しいモノリシックな獣になります。

クラスが複数のシナリオで使用されると機能が不足していますか?あなたの便利な機能でパターンが出現しますか?パターンが出現するまでクラスのインタフェースを正式に拡張することを延期し、この機能を追加する理由があるのは最善です(IMO)。最小限のクラスはメンテナンスが簡単ですが、クライアントにメンテナンスの負担がかかりますので、余分な実装を必要としません。

便利な機能を実装するのが複雑な場合、またはパフォーマンスを大幅に向上させる可能性がある一般的なケースがある場合(たとえば、毎回ロックを使用して一度に1つの要素を処理するのではなく、その場合も考慮する必要があります。

WebBrowserを使用する際に何かが本当に欠落していることが分かった場合もあります。

関連する問題