8

Bjarne Stroustrup 著 The C++ Programming Language という本の中で、著者は関数 inv() を実装しなければならないクラス Matrix を紹介しています。セクション 11.5.1 で、彼はそれを行う 2 つの可能性について語っています。1 つはメンバー関数を作成する方法で、もう 1 つはフレンド関数 inv() を作成する方法です。それから、セクション 11.5.2 の終わりに向かって、彼はフレンド関数を使用するかメンバー関数を使用するかの選択を行うことについて話します。

inv() が m の逆数である新しい Matrix を返すのではなく、実際に Matrix m 自体を逆にする場合、それはメンバーである必要があります。

なぜそうなのですか?フレンド関数でマトリックスの状態を変更して、そのマトリックスへの参照を返すことはできませんか? 関数を呼び出すときに一時行列を渡す可能性があるためですか?..

4

3 に答える 3

13

正直なところ、そのような決定を下す唯一の理由は、構文上の利便性と伝統だと思います。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.
}

どちらも同じ機能を提供し、他の機能が実行できることを変更することはありません。同じ内部が外の世界にさらされます。カプセル化に関しては違いはありません。プライベート状態を変更するフレンド関数があるため、他の関数が異なる方法で実行できることはまったくありません。

実際、ほとんどのクラスを非メンバーフレンド関数(仮想関数と一部のオーバーロードされた演算子はメンバーである必要があります)として記述でき、まったく同じ量のカプセル化を提供します。ユーザーはクラスを変更せずに他のフレンド関数を記述できません。フレンド関数以外の関数はプライベートメンバーにアクセスできます。どうしてそんなことをしないの?これは、C ++プログラマーの99.99%のスタイルに反するものであり、そこから得られる大きな利点がないためです。

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

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

質問の特定の例に対処するにはinv、メンバーであるか非メンバーである必要がありますか?上で概説した親しみやすさの議論のために、私はおそらくそれをメンバーにするでしょう。非スタイル的には、違いはありません。


1。これはC++で発生する可能性は低いです。これは、現時点では重大な変更であり、実質的なメリットがないためです。極端な例として、matrix1x1両方の呼び出しがあいまいになるため、上記で記述したクラスが壊れます。

于 2012-10-10T06:10:33.033 に答える
0

OOD (C++ が促進しようとしている) に固有のカプセル化の哲学では、オブジェクトの状態は内部からのみ変更できると規定されています。構文的には正しいですが (コンパイラーが許可しています)、避けるべきです。

事前定義されたインターフェースを使用せずに、システム全体の要素が相互に変更されると、エラーが発生しやすくなります。オブジェクトのストレージと機能は変更される可能性があり、オブジェクトの特定の部分を使用するコード (巨大になる可能性があります) を探し回るのは悪夢です。

于 2012-10-10T05:24:32.453 に答える
0

フレンドの使用に関しては、次の 2 つの反対意見があります。

外部エンティティがクラスの内部にアクセスできるようになり、内部はメンバーメソッドによってのみ変更される必要があるため、友人はカプセル化を減らすと一方は言います。

反対側は、クラスの内部へのアクセスを外部エンティティの小さなセットに与えることができるため、友人は実際にカプセル化を増やすことができると述べています。彼ら。

どちらの側にも議論の余地がありますが、私は最初のオプションに同意する傾向があります.

あなたの質問については、PherricOxide が彼のコメントで述べたとおりです。クラスの内部属性を変更する必要がある場合は、メンバー メソッドで変更して、カプセル化を適用することをお勧めします。これは、上記の最初のオプションと一致しています。

于 2012-10-10T05:33:54.970 に答える