2012-10-10 11 views
5

Bjarne StroustrupによるC++プログラミング言語の本では、関数inv()を実装しなければならないクラスMatrixを で紹介しています。 11.5.1節で、彼はそのことについて2つの可能性について に話しています。 1つはメンバ関数を作成し、もう1つは にすることです。friend関数をinv()にします。その後、彼はおよそ 友人やメンバ関数を使用するかどうかの選択を行うことを話しセクション11.5.2、の終わりに向かって、彼は言う:関数がオブジェクトの状態を変更する必要があるときに、メンバ関数またはフレンド関数のどちらに移動するか?

INV場合は()実際にはむしろ、反転行列Mそのものを行います がmの逆行列である新しい行列を返すよりも、それはメンバでなければならない。

なぜですか?友人の機能がマトリックスの状態を変更し、そのマトリックスへの参照を に返すことはできませんか?関数を呼び出すときに一時的な行列 を渡す可能性があるからです。

+1

おそらく、友人の機能がばらばらに広がっているのではなく、オブジェクトの中に機能のカプセル化が明確に定義されていると思います。 – PherricOxide

+2

関連するhttp://stackoverflow.com/a/7821482/46642 –

+0

私はここでアップフォースにふさわしい答えは、メンバー機能とメンバー以外の友人の間の実際の違いを指摘し、その違いがどのように決定を下すのに役立つかを説明するべきだと思います。それはより多くの/より少ないカプセル化を提供するので、すべてを離れて波動させる。 –

答えて

9

このような決定を下す唯一の理由は、構文上の利便性と伝統です。私は2つの違いが何であるか(そしてそうではない)、そして決定を下す際にこれらの違いがどのように関係するのかを示すことによって、なぜ説明しますか。

非メンバーフレンド機能とパブリックメンバー機能の違いは何ですか?あまりない。結局のところ、メンバ関数は隠されたthisパラメータとそのクラスのプライベートメンバへのアクセス権を持つ通常の関数に過ぎません。

// what is the difference between the two inv functions? 
// --- our code --- 
struct matrix1x1 { // this one is simple :P 
private: 
    double x; 
public: 
    //... blah blah 
    void inv() { x = 1/x; } 
    friend void inv(matrix1x1& self) { self.x = 1/self.x; } 
}; 
matrix1x1 a; 

// --- client code --- 

// pretty much just this: 
a.inv(); 
// vs this: 
inv(a); 

void lets_try_to_break_encapsulation(matrix1x1& thingy) { 
    thingy.x = 42; // oops, error. Nope, still encapsulated. 
} 

これらは両方とも同じ機能を提供し、他の機能が実行できる機能を変更するものではありません。同じ内部が外部に公開されます。カプセル化の点で違いはありません。私的な状態を変更する友人の機能があるので、他の機能が別々にできることは絶対にありません。

実際、大部分の機能を持つほとんどのクラスを非メンバフレンド関数(仮想関数といくつかのオーバーロード演算子はメンバでなければなりません)として書くことができます。フレンド関数以外の関数がプライベートメンバーにアクセスすることはできません。なぜ私たちはそれをしないのですか?それは99.99%のC++プログラマーのスタイルに反して、それから取られる大きな利点はないからです。

違いは、関数の性質と呼び出す方法にあります。メンバ関数とは、そこからメンバ関数へのポインタを取得できることを意味し、非メンバ関数であるということは、メンバ関数へのポインタを取得できることを意味します。しかし、これはあまり関係ありません(特にstd::functionのようなジェネリック関数ラッパーの場合)。

残りの違いは構文的です。 D言語の設計者は、すべてを統一し、inv(a)のようなオブジェクトを渡してメンバー関数を直接呼び出すことができ、a.inv()のように最初の引数のメンバーとしてフリー関数を呼び出すことができると言っています。そして、クラスは突然それが何かのためにひどくカプセル化されていません。

質問の特定の例に対処するには、invはメンバーですか、それとも非会員ですか?私はおそらくそれをメンバーにしたいと思います。非stylistically、それは違いをもたらさない。


。 C++ではこれが起こりそうにないのは、現時点では大きな変更ではないため、大きなメリットがないからです。極端な例として、私が上に書いたmatrix1x1クラスを壊すのは、両方の呼び出しがあいまいであるためです。

+0

あなたは友人の機能の1つをかなり含んでいますが、誰かがクラスを友人にするときはどうですか?カプセル化を実際に減らすか、または中断さえすると主張することができる。 – Brady

+0

質問に値するのはメンバー関数とフレンド関数です(友人クラスには全く意味がありません)。それがクラスについてのものだったら、とにかくその主張を受け入れるために、まだその一例が必要です。 –

+0

良い点。私の答えは、一般的な友達(クラスと機能)を指していました。 STLはいくつかの場所で友人機能を使用していますが、友人のクラスを使用しているとは思われません。 – Brady

0

OOD(C++が推進しようとする)に内包されているカプセル化の哲学は、オブジェクトの状態を内部からしか変更できないように指示します。 構文的には正しいですが(コンパイラで許可されています)、避けてください。

システム全体の要素が、あらかじめ定義されたインターフェイスを使用せずに相互に変更されるようにするのは誤りです。 オブジェクトの格納と機能は、オブジェクトの特定の部分を使用するコード(それは巨大かもしれない)が悪夢になることを変えることがあります。使用して友人に関する2つの対向する引数があり

0

です:

片側は、今あなたがせている外部エンティティは、クラスの内部にアクセスし、内部のみメンバメソッドによって変更されなければならないので、友人がカプセル化を減らすと言います。

もう1つの側面は、クラスの内部を小さな外部エンティティのセットにアクセスできるため、友人が実際にカプセル化を増やすことができるため、内部クラス属性を全員に公開する必要がなくなるため、それらにアクセス/操作することができます。

両面について議論することができますが、私は最初の選択肢に同意する傾向があります。

あなたの質問は、PherricOxideがコメントしたように:クラスの内部属性を変更する必要がある場合は、メンバメソッドで行う方がカプセル化が強化されます。これは上記の最初のオプションとインラインです。

+0

なぜdownvote ?? – Brady

関連する問題