すいません。まず、この話題はC++言語限定とさせて下さい。広げると収拾がつかなくなる予感がしますので。
下記のようなメンバ変数mMemberへのアクセス方法について、皆さんはどちらで定義しますか?
たぶんケースバイケースと思います。どんな時にprivate定義してアクセサを提供(Foo型)し、どんな時にpublic定義(Bar型)しますか?
C++
1class Foo 2{ 3private: 4 int mMember; 5public: 6 int getMember() const {return mMember;} 7 void setMember(int iMember) {mMember=iMember;} 8 : 9}; 10 11struct Bar 12{ 13 int mMember; 14 : 15};
FooもBarと同様にmMemberを事実上全て開示してます。ですので、Foo型を用いるメリットはmMemberがアクセスされる際に何か処理を追加してもI/Fを変えないで済むことだけです。ですので、処理を追加する可能性がほぼ想定されないなら、無駄に複雑にしないためにBar型を使うべきです。
しかし、構造体(データを保持することが主目的)として設計したクラスであれば良いのですが、オブジェクト指向的に設計したクラスでは抵抗を感じてしまい、躊躇してます。
そこで、参考にさせて頂きたく、皆さんのご意見をお聞かせ下さい。
##結果報告
この議論を通じて、やっと自分なりの方針を明確にできました。
皆さん、ありがとうございます。
ベストアンサーは、C++らしい方針を最も明確に記載して頂けたcatsforepawさんにさせて頂きました。
また、「ブレーク貼れるようにアクセサ」という使い方に気づかせて頂けたこともありがたいです。
【検討のポイント】
私はシンプルイズベスト信者なので、メリットのない複雑さは悪と考えます。
なので、メリットもないのにアクセサを設けるのは悪なわけです。
ということは、アクセサを設けるメリットは何か?がポイントになります。
なお、アクセスされたタイミングで何らかのアクションを行うようなケースはメリットもなにも必須事項なので検討不要ですね。
また、そのような機能の追加も含め、何らかの変更が予想されるケースでは、アクセサを設けるメリットが明確ですので、こちらも検討不要です。
変更が予想されない時でも、アクセサ化するメリットがあるのか?が検討のポイントとなります。
【アクセサを設けるメリットのまとめ】
皆さんの意見のうち、【検討のポイント】的にメリットが明確なものを選択させて頂き、私が理解した内容で纏めてみました。(多少違っているかも知れません。その時はごめんなさい。)
raccyさん
メンバ変数へのアクセスは原則Read Onlyとするので、常にアクセサを使う。
私的な見解:
この基準(コーディング規約かも?)により、多少不慣れな人がいても比較的安全に開発を進めることができると言うメリットがあると感じます。
大勢の人がメンテナンスするようなプロジェクトで特に有用ですね。
catsforepawさんとyohhoyさん
変更が予想されないとはいえ可能性は0ではないので、アクセス時の処理変更の影響範囲が大きい場合、その影響を軽減するためにアクセサを設ける。
また、多くの場所からアクセスされる時はアクセサを設けるとデバッグしやすい。
私的な見解:
逆に、変更しても影響範囲が狭い場合はアクセサを設けるメリットが小さいのでpublicのままでも十分ということです。
そして、C++の場合は比較的熟練したプログラマが担当するケースも少なくないと思います。そのようなケースでは密結合部分についてpublicとして開示した方が、見通しも良くなりポインタ経由アクセス等、使えるテクニックも増えるのでより好ましいと感じます。
【私的な方針のまとめ】
私自身が担当しているプロジェクトは小規模・少数精鋭型が多いです。
そこで、下記方針を選択することにしました。
- メンバ変数が少しの場所(数カ所程度?)からしかアクセスされないものについては、publicとする。
- 外部に公開する部分も含め、これに該当しない場合はアクセサ化する。
あくまでも方針なのでそれなりに例外もあるとは思いますが、これで罪悪感を感じず(笑)にpublic定義できます。
######ところで、何故にC++限定だったのか?
最初に「この話題はC++言語限定とさせて下さい。広げると収拾がつかなくなる予感がしますので。」と記載させて頂きました。いまいち明確に表現できてなかったのですが、今回の議論を通じてやっと言語化できました。
C++言語でのプログラミングでは、可読性やメンテナンス性も当然熟慮しますが、高速性もかなり重視しており、多少(場合によっては大きく)可読性/メンナナンス性を劣化させてでも速度を取る言語です。ポインタはその典型例と思います。更に参照とかconst参照とか右辺値参照とかもうパニック・レベルですね。まして、テンプレート・メタ・プログラミングと来た日にはorz。
この辺がスピードを犠牲にして可読性やメンテナンス性に注力しているJavaやC#のような言語と大きく使い方が異なる部分と思います。
その結果、アクセサを定義する/しないの判断基準もそれなりに異なっていることが予想できるため、C++での方針を形作りたい自分にとっては、言語を限定した方がよいということだったのです。
それでは、最後にもう一度、Stripeさんも含め、ご回答頂いた皆さんありがとうございました。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答10件
0
private原理主義者な私は、常にprivateにしています。
まずもって、クラスの設計の仕方からpublicにするという行程が欠けています。
- いいクラス名を考える。
- クラスが提供するメソッドを考える。(C++であろうとメンバー関数などという言葉は使わない!)
- メソッドを実現するためにはどのようなデータを内部に持つ必要があるかを考える。この内部データはメンバー変数として実装するが、外には見せないことが前提、つまりはprivateにする。
- 他クラスとの連携で、内部データをそのまま渡した方がスムーズに行く場合のみ、getterを作ることを考える。
- 他クラスとの連携で、内部データをピンポイントで書き換える事が実装上どうしても必要な場合は、本当に必要なのか脳内会議を開いて、それでも必要と結論ができたときのみ、setterをしぶしぶ作ることを考える。
これがいいのかは私にはわかりませんが、たぶん、プログラミングを始めた頃にJavaの色んな本でpublicは悪と教え込まれ、その後にRubyに洗脳されてしまったからだと思います。C++をはじめからやっておけば、違ったやり方をしていたのかも知れません。
なお、構造体は全く別枠で考えています。
投稿2015/11/30 12:45
総合スコア21741
0
ベストアンサー
例に挙げているような単純なアクセサは、作った方が良いと思われる積極的な理由がなければ、わざわざ作ったりはしません。内部的な(使用箇所が限定されるような)クラスでは作らないことが多いです。
ライブラリや共通部品として公開するような使用範囲の広いクラスでは、基本的には以下のような理由からアクセサを作ります。
- デバッグがしやすくなる(テストコードを書いたり、ブレークポイントを置いたり)
- セーフティガード(ポインタ経由で想定外の場所からメンバ変数を読み書きされないように)
- アクセス時の処理を変更した場合の影響範囲の広さを考慮
投稿2015/11/29 00:51
総合スコア5944
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
>構造体(データを保持することが主目的)として設計したクラスであれば良いのですが
と述べているようにそのような設計であれば構造体でいいんじゃないですか?
メソッドの追加が必要になるということは再設計になるので、たとえばBar構造体をメンバに含むクラスFooを新しく作ればいいだけだと思います。
投稿2015/11/28 17:31
総合スコア1456
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/11/29 16:08
2015/11/29 22:38

退会済みユーザー
2015/11/30 21:40
2015/12/01 12:21

0
publicメンバは、constの場合のみですね…
「アクセサを用意する」という方針以外考えられません。
理由はいろいろ考えられますが、いくつか書いてみると…
・mMemberの型を変更する可能性
・mMemberの正当性をチェックしたい
・暗黙の型変換を防ぐ
#Fooがconstである場合、例のままだと読み出しアクセスさえできませんね。
C++
1 int getMember() const { return mMember; }
投稿2015/12/01 05:30
総合スコア13
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/12/02 01:52
2015/12/02 03:42 編集

0
今現在、読み書きで使うのならpublicなメンバにして、アクセサの必要が生じた時点で、privateにしてアクセサに変更すれば宜しいかと思います。
将来の仕様変更においても、コンパイラが修正場所を漏れなくエラーメッセージとして報告してくれますから、人間の注意力に頼らない非常に安全な修正ができるはずです。
私は、積もり積もった複雑さ、猥雑化(コードの読みにくさを)の方を問題にします。
C++
1class int_acc { 2private: 3 int aaaa; 4public: 5#if 1 6 int& operator=(int i) { 7 this->aaaa = i; 8 return this->aaaa; 9 } 10#endif 11 operator int(){ 12 return this->aaaa; 13 } 14}; 15class cfoo { 16public: 17 int_acc abc; 18}; 19void bbbb() 20{ 21 cfoo a; 22 int i,j,k; 23 a.abc = 3; 24 i = a.abc; 25}
これはアクセサ?
投稿2015/11/29 02:34
編集2015/11/30 12:52
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/11/29 02:50

退会済みユーザー
2015/11/29 04:52
2015/11/29 05:08

退会済みユーザー
2015/11/29 09:40
2015/11/29 16:25

退会済みユーザー
2015/11/30 12:53 編集

退会済みユーザー
2015/11/30 21:46 編集

0
C++に限った話ではありませんが、構造体を使いたければ構造体を定義すればいいだけだし、オブジェクトを使いたければオブジェクトを定義するだけです。
結局のところ、あなたは何をしたいんですか?
投稿2015/11/28 16:09
総合スコア2183
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
こんにちは。もしかしてすでに似た趣旨のご回答をされている方もおられるかもしれませんが...
C++では、クラスのメンバーにおいてアクセス修飾子を指定しない場合 private になりますので、クラスについて基本的にはメンバーを隠匿するような使用法を言語設計者は意図しているのだろうと思います。
私の経験的にですが、vga640x480さんが仰られる内容や、デバッグのしやすさなどから、アクセッサを経由させたほうが保守性が向上しています(改修などで、あとから楽)。
たとえば、メンバー変数の型のほうを変更した場合も、公開する変数型を同じままに保つことができます。
オブジェクトやデータをさらけ出してひとかたまりとして扱いたい場合は、既定のアクセスレベルがpublicである、構造体を私なら使用します(class から structにコードを変えます)。
ご質問にもどりますと、私なら躊躇せずメンバー変数は隠匿し、アクセッサを定義します。すべて公開したいデータ(オブジェクトや変数)の集まりなら、構造体にします。すぐ捨てるサンプル的なコードならともかく、面倒ですがクラスを定義すると同時(早い段階)でアクセッサも用意します。
余談ですが、C++でも.NET Frameworkのマネージドアプリケーションを作れますけれども、オブジェクト間のバインド機構を使うときにプロパティ(アクセッサ)である必要がある(フィールド(メンバー変数)は使用不可)だったりするので、 .NET 開発者もclassオブジェクトに関しては同様の考えを持っているのかな...と感じます。いちいちアクセッサを書くことは面倒かもしれませんが、IDEがずいぶん進化していて助けられます。
趣旨からずれていたらすみません。
投稿2015/12/02 01:40
編集2015/12/02 02:06総合スコア728
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
ベストプラクティスパターン
(ケント・ベック著)
という本がありまして、
本で使用している言語がC++
ではないので申し訳ないのですが、
インスタンス変数を直接アクセス
すべきなのか、それともメソッドを
必ず介すのがいいのかという
議論が紹介されていました。
どちらが良いとか悪いとかではなく、
どちらも一長一短があり、
難しい議論です。ます。
お読みになってみては
いかがでしょうか?
蛇足ながら、
私個人はこの本を読了し、
必ずメソッドを介したほうが
良いと結論を出しました。
投稿2015/12/01 11:23
総合スコア101
0
構造体(データを保持することが主目的)として設計したクラスであれば良いのですが、オブジェクト指向的に設計したクラスでは抵抗を感じてしまい、躊躇してます。
個人的には、言及されているものとおおよそ同じ指針をとっています。使い分けの線引きラインとしては、「責任分界の強度」を用いています。外部仕様のようにインタフェースがはっきりとしている場合には、厳密な使い分けを心がけますが、内部実装のように結合度が高い場合には、曖昧な使い分けになります。
ついでにstructとclassの使い分けもすることが多いです。言語仕様的にはデフォルトでpublic/privateという差しかありませんが、コンパイラでは無く人(プログラマ)に意味を伝える目的で使い分けています。
単なるデータの集まりを表す場合は、publicメンバをもつstructとして宣言します。基本的にメンバ関数は実装しません。
- データコンテナ型のようにある程度複雑なデータ構造を表現する場合、データメンバを直接privateで公開せずに隠蔽し、より高位の操作をアクセサとしてpublicメンバ関数化することがあります。
- ライブラリ内部実装向け入れ子(Inner)クラス等では、publicメンバ+実装上便利なメンバ関数を実装することがあります。
いわゆるオブジェクト指向的なクラスの場合は、全て非publicメンバをもつclassとして宣言します。データメンバへは必ずアクセサ経由とします。
- 上記繰り返しとなりますがライブラリ内部実装向けのクラス等では、(手抜きのため)一部をpublicメンバ化することもあります。
余談ですが、アクセサのメリットとして挙がっている、排他制御(スレッドセーフ性)の後付けはおすすめしません。あるクラスがスレッドセーフ操作を提供するか否かは、決して内部の実装詳細などではなく、そのクラス外部仕様の一部であるべきです。後付けでの排他制御実装は論理破綻、もしくは実行時の不安定動作リスクに繋がります。
投稿2015/11/30 02:37
総合スコア6191
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
私の場合クラスと構造体の使い分けは「データ保持以外に機能を持たせるかどうか」という点です。
データ保持用のために設計した場合、構造体として定義してメンバが特殊でどうしても初期化処理が必要な場合はコンストラクタを書くこともありますが、基本的にはメンバ関数は持たせません。
データ保持以外になんらかの演算をさせたい場合、クラスとして設計してメンバ変数を隠蔽します。単純なアクセサも書きますが、get/setともに、範囲チェックなどの処理も含めたものにすることが多いです。
投稿2015/11/28 22:06
総合スコア3041
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/11/30 13:54
2015/12/01 15:15
2015/12/02 04:25