5

SutterとAlexandrescuは、 「非メンバーの非フレンド関数を作成することを好む」というタイトルの(そうでない場合は)優れた本C ++ Coding Standardsのアイテム44で、クラスのメンバーに本当にアクセスする必要がある関数のみをそのクラスのメンバーにすることを推奨しています。メンバー関数のみを使用して記述できる他のすべての操作は、クラスの一部であってはなりません。彼らは非会員であり、非友人でなければなりません。議論は次のとおりです。

  • クラスの内部にアクセスする必要のあるコードが少ないため、カプセル化が促進されます。
  • 一部の関数がメンバーであるかどうかを毎回推測する必要がないため、関数テンプレートの作成が容易になります。
  • クラスを小さく保つため、テストと保守が容易になります。

これらの引数には値がありますが、大きな欠点があります。IDEがこれらの関数を見つけるのに役立ちません。ある種のオブジェクトがあり、そのオブジェクトで使用できる操作を確認したい場合は、「pMysteriousObject->」と入力してメンバー関数のリストを取得することはできなくなります。

クリーンなデザインを維持することは、最終的にはプログラミング作業を楽にすることです。しかし、これは実際に私のものをはるかに難しくします。

だから私はそれが本当にトラブルの価値があるのだろうかと思っています。どのように対処しますか?

4

7 に答える 7

5

Scott Meyers は Sutter と同様の意見を持っています。こちらを参照してください。

彼はまた、次のことを明確に述べています。

「Jack Reeves は、さまざまな文字列のようなクラスに関する彼の研究に基づいて、一部の関数は、たとえそれらが非フレンド非メンバーである可能性があるとしても、非メンバーにすると正しく「感じられない」ことを観察しました。「最高の」インターフェースクラスは、カプセル化の程度が 1 つである多くの競合する懸念のバランスを取ることによってのみ見つけることができます。」

関数がメンバー関数であることが「理にかなっている」ものである場合は、メンバー関数にします。同様に、それが実際にはメイン インターフェイスの一部ではなく、非メンバーであることが「理にかなっている」場合は、そうしてください。

1 つの注意点として、operator==() などのオーバーロードされたバージョンでは、構文は同じままです。したがって、この場合、プライベートメンバーへのアクセスが本当に必要でない限り、クラスと同じ場所で宣言された非メンバー非フレンド浮動関数にしない理由はありません(私の経験ではめったにアクセスしません)その場合でも、operator!=() を非メンバーとして、operator==() に関して定義できます。

于 2008-09-26T04:37:20.137 に答える
5

Sutter、Alexandrescu、Meyers の 3 人が、C++ の品質のために他の誰よりも多くのことを行ったと言っても過言ではないと思います。

彼らが尋ねる簡単な質問は次のとおりです。

ユーティリティ関数にパラメーターとして 2 つの独立したクラスがある場合、どのクラスがメンバー関数を「所有」する必要がありますか?

別の問題は、問題のクラスが制御下にある場合にのみメンバー関数を追加できることです。クラス定義を再度開くことができないため、 std::string に対して作成するヘルパー関数は非メンバーである必要があります。

これらの例の両方について、IDE は不完全な情報を提供するため、「昔ながらの方法」を使用する必要があります。

世界で最も影響力のある C++ の専門家が、クラス パラメーターを持つ非メンバー関数はクラス インターフェイスの一部であると考えていることを考えると、これはコーディング スタイルではなく、IDE の問題です。

IDE は 1 つか 2 つのリリースで変更される可能性が高く、この機能を追加してもらうことさえできるかもしれません。現在の IDE に合うようにコーディング スタイルを変更すると、将来、拡張不可能/保守不可能なコードでより大きな問題が発生する可能性があります。

于 2008-09-26T10:17:33.907 に答える
3

これについては、SutterとAlexandrescuに反対する必要があります。関数の振る舞いがクラスの責任のfoo()範囲内にある場合は、の一部である必要があると思います。Barfoo()bar()

foo()のメンバーデータに直接アクセスする必要がないという事実Barは、それが概念的にの一部ではないことを意味するわけではありませんBar。また、コードが適切に因数分解されていることを意味する場合もあります。他のメンバー関数を介してすべての動作を実行するメンバー関数があることは珍しくありません。なぜそうあるべきかわかりません。

周辺関連の機能をクラスに含めるべきではないことに完全に同意しますが、クラスの責任の中核となるものがあれば、メンバーデータを直接いじくり回しているかどうかに関係なく、メンバーにならない理由はありません。

これらの特定のポイントについて:

クラスの内部にアクセスする必要のあるコードが少ないため、カプセル化が促進されます。

実際、内部に直接アクセスする関数は少ないほど良いです。つまり、メンバー関数に他のメンバー関数を介して可能な限り多くのことを実行させることは良いことです。因数分解された関数をクラスから分割すると、ハーフクラスが残ります。これには、多数の外部関数が役立つ必要があります。因数分解された関数をクラスから引き離すことも、因数分解された関数の記述を思いとどまらせるようです。

一部の関数がメンバーであるかどうかを毎回推測する必要がないため、関数テンプレートの作成が容易になります。

私はこれをまったく理解していません。たくさんの関数をクラスから引き出すと、関数テンプレートにより多くの責任を負わせることになります。クラスからプルされたほとんどの関数がテンプレートに変換されると想定しない限り、クラステンプレート引数によって提供される機能はさらに少ないと想定する必要があります(ugh)。

クラスを小さく保つため、テストと保守が容易になります。

ええと、確かに。また、テストおよび保守するための多くの追加の外部関数を作成します。私はこれの値を見ることができません。

于 2008-09-25T20:06:27.680 に答える
1

確かに、外部関数はインターフェースの一部であってはなりません。理論的には、クラスにはデータのみが含まれ、実用的な関数ではなく、意図されたもののインターフェースを公開する必要があります。インターフェイスにユーティリティ関数を追加すると、クラスコードベースが大きくなり、保守性が低下します。私は現在、約50のパブリックメソッドを持つクラスを維持していますが、それは非常識です。

さて、実際には、これを実施するのは簡単ではないことに同意します。多くの場合、クラスに別のメソッドを追加する方が簡単です。既存のクラスに新しいメソッドを追加するだけのIDEを使用している場合はさらに簡単です。

クラスをシンプルに保ち、外部関数を一元化できるようにするために、クラスまたは名前空間でさえも機能するユーティリティクラスをよく使用します。まず、データをラップし、可能な限り単純なインターフェイスを公開するクラスを作成します。次に、クラスで行う必要のあるすべてのタスクに対して新しいクラスを作成します。

例:クラスPointを作成してから、クラスPointDrawerを追加してビットマップに描画し、PointSerializerを追加して保存します。

于 2008-09-25T20:17:14.690 に答える
0

それらに共通のプレフィックスを付けると、入力するとIDEが役立つ可能性があります

::prefix

また

namespace::prefix
于 2008-09-25T20:10:06.300 に答える
0

多くの OOP 言語では、非フレンド非クラス メソッドは、何にも接続されていない孤児院に住む三流市民です。私がメソッドを書くとき、彼らが歓迎され、助けられていると感じられる可能性が最も高い、良い親、つまり適切なクラスを選ぶのが好きです。

于 2008-09-25T21:23:47.417 に答える
-1

IDEが実際にあなたを助けていると思っていたでしょう。

IDEは、保護された関数をリストから隠しています。これは、クラスの設計者が意図したとおりに一般に公開されていないためです。

クラスのスコープ内にいてthis->と入力した場合は、保護された関数がリストに表示されます。

于 2008-09-26T04:09:00.547 に答える