82

私は現在Qtで働いているのでC++です。プライベートデータメンバーとパブリックメンバー関数を持つクラスがあります。クラスで利用可能なデータメンバー用の公開ゲッターとセッターがあります。

ここで私の質問は、クラスにデータメンバーのゲッターとセッターがある場合、それらのデータメンバーをプライベートにすることのポイントは何ですか?基本クラスにプライベートデータメンバーを含めることは論理的に聞こえることに同意します。しかし、それ以外に、プライベートメンバーがいること、そして彼らのゲッターやセッターがいることは、私にとって論理的なものではないようです。

または、代わりに、すべての変数をパブリックにして、ゲッターとセッターをまったく必要としないようにすることはできますか?それらを持っているのは良い習慣ですか?プライベートメンバーを使用するとデータの抽象化が確実になりますが、ゲッターとセッターを使用すると、実際にはこれらの変数に非常に簡単にアクセスできます。これに関するポインタは大歓迎です。

4

15 に答える 15

82

ない。物事を行うメソッドが必要です。これらのいずれかが特定の内部変数に対応している場合は素晴らしいことですが、これをクラスのユーザーに通知するものは何もないはずです。

プライベート データはプライベートであるため、必要に応じていつでも実装を置き換えることができます (完全な再構築を行うこともできますが、それは別の問題です)。Genie をボトルから出すと、元に戻すことができなくなります。

編集:別の回答に対して行ったコメントに続いて。

ここでの私のポイントは、あなたが間違った質問をしているということです。ゲッター/セッターの使用またはパブリック メンバーの使用に関するベスト プラクティスはありません。特定のオブジェクトに最適なものと、それが特定の現実世界のもの (またはゲームの場合はおそらく想像上のもの) をモデル化する方法だけがあります。

個人的には、ゲッター/セッターは 2 つの悪のうち小さいほうです。ゲッター/セッターを作成し始めると、人々はどのデータを表示し、どのデータを表示してはならないかについて批判的な目でオブジェクトを設計しなくなります。public メンバーの場合は、すべてを公開する傾向になるため、さらに悪化します。

代わりに、オブジェクトが何をするのか、何かがそのオブジェクトであることが何を意味するのかを調べてください。次に、そのオブジェクトへの自然なインターフェイスを提供するメソッドを作成します。その自然なインターフェースには、ゲッターとセッターを使用していくつかの内部プロパティを公開することが含まれます。しかし、重要な部分は、事前にそれについて考え、設計上の正当な理由でゲッター/セッターを作成したことです。

于 2010-06-04T19:13:34.310 に答える
39

いいえ、まったく同じではありません。

クラス インターフェイスへのさまざまなアプローチによって達成できる、さまざまなレベルの保護/実装隠蔽があります。


1. 公開データ メンバー:

  • データメンバーへの読み取りと書き込み (const でない場合) の両方のアクセスを提供します
  • データ オブジェクトが物理的に存在し、物理的にこのクラスのメンバーであるという事実を公開します (そのデータ メンバーへのポインターからメンバーへの型のポインターを作成できます)。
  • データメンバーへの左辺値アクセスを提供します (メンバーへの通常のポインターを作成できます)


2. データの一部への参照を返すメソッド (おそらくプライベート データ メンバーへ):

  • データへの読み取りと書き込み (const でない場合) の両方のアクセスを提供します
  • データオブジェクトが物理的に存在するという事実を公開しますが、それが物理的にこのクラスのメンバーであることを公開しません (データへのポインターからメンバーへの型のポインターを作成することを許可しません)
  • データへの左辺値アクセスを提供します (データへの通常のポインタを作成できます)


3. ゲッターおよび/またはセッター メソッド (プライベート データ メンバーにアクセスする可能性があります):

  • プロパティへの読み取りおよび/または書き込みアクセスを提供します
  • このクラスに物理的に存在することは言うまでもなく、データオブジェクトが物理的に存在するという事実を公開しません(そのデータへのポインターからメンバーへの型のポインター、またはそのことに関するあらゆる種類のポインターを作成することを許可しません)
  • データへの左辺値アクセスを提供しません (データへの通常のポインターを作成することを許可しません)

getter/setter アプローチは、プロパティが物理オブジェクトによって実装されているという事実さえ明らかにしません。つまり、getter/setter ペアの背後に物理データ メンバーがない可能性があります。

上記を考慮すると、ゲッターとセッターのペアがパブリック データ メンバーと同じであると誰かが主張するのを見るのは奇妙です。実際、それらには共通点はありません。

もちろん、それぞれのアプローチにはバリエーションがあります。たとえば、getter メソッドはデータへの const 参照を返す場合があり、(2) と (3) の間のどこかに配置されます。

于 2010-06-04T19:29:11.120 に答える
25

データ項目ごとにゲッターとセッターがある場合、データをプライベートにする意味はありません。そのため、データ項目ごとにゲッターとセッターを用意するのは悪い考えです。std :: stringクラスについて考えてみます。これには(おそらく)1つのゲッターとsize()関数があり、セッターはまったくありません。

または、BankAccountオブジェクト について考えてみSetBalance()ましょう。現在のバランスを変更するためのセッターが必要ですか?いいえ、ほとんどの銀行はそのようなことを実行してくれてあなたに感謝しません。代わりに、のようなものが必要ですApplyTransaction( Transaction & tx )

于 2010-06-04T19:10:20.103 に答える
11

ゲッターとセッターを使用すると、プライベートメンバーからの入出力にロジックを適用して、データへのアクセスを制御できます(OO用語を知っている人へのカプセル化)。

パブリック変数は、クラスのデータを公開したままにして、制御されていない、検証されていない操作を可能にします。これは、ほとんどの場合、望ましくありません。

これらのことについても長期的に考える必要があります。現在検証が行われていない可能性がありますが(これがパブリック変数が良いアイデアのように思われる理由です)、将来的に追加される可能性があります。事前にそれらを追加するとフレームワークが離れるので、検証によって依存コードがこのように破損しないことは言うまでもなく、raodのリファクタリングが少なくなります)。

ただし、これは、すべてのプライベート変数に独自のゲッター/セッターが必要であることを意味するものではないことに注意してください。ニールは彼の銀行の例で、ゲッター/セッターが意味をなさないことがあるという良い点を挙げています。

于 2010-06-04T19:09:58.047 に答える
11

データを公開します。いつか「ゲッター」または「セッター」でロジックが必要になる (かなりありそうもない) イベントでは、データ型をオーバーロードoperator=および/またはoperator T(T = 現在使用している型は何でも)プロキシ クラスに変更できます。必要なロジックを実装します。

編集: データへのアクセスを制御することがカプセル化を構成するという考えは、基本的に誤りです。カプセル化とは、データへのアクセスを制御するのではなく、実装の詳細を隠すことです (一般に!) 。

カプセル化は抽象化を補完します。抽象化はオブジェクトの外部から見える動作を扱い、カプセル化はその動作の実装方法の詳細を隠すことを扱います。

ゲッターまたはセッターを使用すると、実際には抽象化のレベルが下がり、実装が公開されます。クライアント コードは、この特定のクラスが論理的に "データ" を関数のペア (ゲッターとセッター) として実装することを認識している必要があります。上記で提案したようにプロキシを使用すると、実際のカプセル化が提供されます。1 つのあいまいなまれなケースを除いて、論理的にデータの一部であるものが実際には関数のペアを介して実装されているという事実が完全に隠されます。

もちろん、これは文脈にとどめる必要があります。一部のクラスでは、「データ」はまったく適切な抽象化ではありません。一般的に言えば、データの代わりに高レベルの操作を提供できる場合は、それが望ましいです。それにもかかわらず、最も使用可能な抽象化がデータの読み取りと書き込みであるクラスがあります。その場合、(抽象化された) データは他のデータと同じように見えるようにする必要があります。値の取得または設定にビットの単純なコピー以上のことが含まれる可能性があるという事実は、ユーザーから隠されるべき実装の詳細です。

于 2010-06-04T19:13:13.920 に答える
5

ロジックが単純で、変数の読み取り/書き込み時に他に何もする必要がないことが確実な場合は、データを公開しておくことをお勧めします。C++ の場合、クラスではなく構造体を使用して、データが公開されていることを強調します。

ただし、データ メンバーにアクセスするときに他のことを行う必要がある場合や、後でこのロジックを自由に追加したい場合がよくあります。この場合、ゲッターとセッターは良い考えです。変更は、コードのクライアントに対して透過的になります。

追加機能の簡単な例 - 変数にアクセスするたびにデバッグ文字列をログに記録したい場合があります。

于 2010-06-04T19:16:44.957 に答える
5

カプセル化の問題 (十分な理由です) は別として、getter/setter がある場合、変数が設定/アクセスされるたびにブレークポイントを設定するのは非常に簡単です。

于 2010-06-04T19:18:14.267 に答える
4

getter や setter ではなくパブリック フィールドを使用する理由は次のとおりです。

  1. 不正な値はありません。
  2. クライアントはそれを編集することが期待されています。
  3. object.XY = Z などを書けるように。
  4. 値が単なる値であり、それに関連する副作用がないことを強く約束すること (そして将来もそうではないこと)。

作業しているソフトウェアの種類によっては、これらはすべて非常に例外的なケースである場合もあれば (実際に遭遇したと思う場合はおそらく間違っている場合もあります)、常に発生する場合もあります。それは本当に依存します。

(値ベースのプログラミングに関する 10 の質問から。)

于 2015-06-25T14:07:14.513 に答える
3

厳密に実用的には、すべてのデータ メンバーを非公開にすることから始めて、そのゲッターとセッターを非公開にすることをお勧めします。他の世界 (つまり、「(l) ユーザー コミュニティ」) が実際に何を必要としているのかがわかったら、適切なゲッターやセッターを公開したり、適切に制御されたパブリック アクセサーを作成したりできます。

また、(Neil の利益のために) デバッグ時に、特定のデータ メンバーが読み書きされるときに、デバッグ プリントやその他のアクションをハングアップするための便利な場所があると便利な場合があります。ゲッターとセッターを使えば、これは簡単です。公開データ メンバーの場合、これは非常に面倒なことです。

于 2010-06-04T19:16:06.783 に答える
2

ゲッターとセッターは、ほとんどのプログラミング言語で意図的に冗長であると常に考えていました。特に、それらの使用について2回考えさせるためです。なぜ、発信者はクラスの内部動作について知る必要があるのでしょうか。 。

于 2010-06-04T19:27:33.953 に答える
1

ゲッターとセッターを使用すると、ユーザーに値を与える方法を変更できます。

次の点を考慮してください。

double premium;
double tax;

次に、このpremium値を使用してあらゆる場所にコードを記述し、プレミアムを取得します。

double myPremium = class.premium;

仕様が変更されたばかりで、ユーザーの観点からプレミアムである必要がありますpremium + tax

そのpremium値がコードで使用されているすべての場所を変更し、それに追加taxする必要があります。

代わりに、そのように実装した場合:

double premium;
double tax;

double GetPremium(){return premium;};

すべてのコードが使用GetPremium()され、tax変更は 1 行になります。

double premium;
double tax;

double GetPremium(){return premium + tax;};
于 2010-06-04T19:33:33.237 に答える
1

パブリック データ メンバーを持たないことをお勧めします (POD 構造体を除く)。また、すべてのデータ メンバーに対してゲッターとセッターを用意することもお勧めしません。むしろ、クラスのクリーンなパブリック インターフェイスを定義してください。これには、プロパティ値を取得および/または設定するメソッドが含まれる場合があり、それらのプロパティはメンバー変数として実装される場合があります。ただし、すべてのメンバーに対してゲッターとセッターを作成しないでください。

インターフェイスを実装から分離して、クラスのユーザーがコードを変更しなくても実装を変更できるようにするという考え方です。ゲッターとセッターを介してすべてを公開する場合、公開データを使用するよりも何も改善されていません。

于 2010-06-04T19:14:36.317 に答える
0

戻り値は、ゲッターとセッターの使用にも影響します。変数の値を取得するか、プライベート データ メンバー変数にアクセスするかの違いです。値渡しは整合性を維持し、参照渡しまたはポインター渡しはそれほどではありません。

于 2010-06-04T19:15:59.340 に答える
0

ゲッターとセッターは主に、メンバーの取得方法と設定方法を制御できるようにするために存在します。ゲッターとセッターは、特定のメンバーにアクセスする方法としてのみ存在するわけではありませんが、メンバーを設定しようとする前に、おそらく特定の条件を満たしていることを確認するため、または取得した場合にそのコピーを返すことを制御できるようにするためです非プリミティブ型の場合のメンバー。全体として、データ メンバーとやり取りする方法をパイプライン処理する場合は、g/s'ers を試して使用する必要があります。パイプラインを使用しないと、メンバーがアドホックな方法で使用されます。

于 2014-10-27T19:28:31.857 に答える