質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

6回答

5910閲覧

C++ カプセル化のこと

aidida

総合スコア14

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2016/12/17 11:51

編集2022/01/12 10:55

こんにちは。

最下部に5つ質問がありますので、答えられる範囲で
お願いします。全部解答してくださる方大歓迎です(#^^#)

C++だとカプセル化ができますが、
ゲッター、セッターを使わずに
クラスのprivateメンバを直接、そのクラスのインスタンスから
変更したり取得したりすることが可能です。

クラス型の変数をインスタンス化せずに
そのprivateメンバにアクセスすること自体はできます。

以上のことからカプセル化およびゲッター・セッターってどういったときに
使うものなのだろうかと疑問がわいたので質問します。

まず、私の見解は間違ってますか?
カプセル化およびゲッター・セッターは必要なものでしょうか?
必要だとしたらあなたならどういった用途で使いますか?
C++が初心者なので、他言語との違いを含めてアドバイスください。
大規模開発にカプセル化が必要だということですか?

よろしくお願いしますー

c++

1**Sample.h** 2 3#ifndef _SAMPLE_H_ 4#define _SAMPLE_H_ 5 6class Sample{ 7public: 8 int a; // publicなメンバ変数 9private: 10 int b; // privateなメンバ変数 11public: 12 void func1(); 13private: 14 void func2(); 15}; 16 17#endif // _SAMPLE_H_

c++

1**Sample.cpp** 2 3#include "Sample.h" 4#include <iostream> 5 6using namespace std; 7 8void Sample::func1(){ 9 cout << "func1" << endl; 10 a = 1; 11 b = 1; 12 func2(); // func2ないから、func1を呼び出す 13} 14void Sample::func2(){ 15 a = 2; 16 b = 2; 17 cout << "a=" << a << "," << "b=" << b << endl; 18}

c++

1**main.cpp** 2 3#include "Sample.h" 4#include <iostream> 5 6using namespace std; 7 8int main(){ 9 Sample s;//←このsがインスタンス化されてないものと思ってました 10 s.a = 1; 11 //s.b = 2; 12 s.func1(); 13 //s.func2(); 14}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2016/12/17 13:33 編集

学び始めのためか、用語を不正確に使っていて閲覧者に正確に伝わってないと思います。多分具体的なコードを書いて、「(1)の行でやっているように」といった説明をすれば閲覧者にも意味がくみ取れると思います。
KSwordOfHaste

2016/12/18 01:19

コードの明示で「Sample s;」がインスタンスの生成である点に気づかれたことがわかります。これを勘違いしていたため、「インスタンスを生成する前でもpublicメンバー関数にアクセスできるからその中からprivateにアクセスできる」と勘違いされていたのだろうと思います。誤解が解消されてみると、Chironianさんが回答されているカプセル化・getter/setterについての回答が腑に落ちるのではないでしょうか?
guest

回答6

0

こんにちは。

まず、私の見解は間違ってますか?

たぶん間違ってます。前提が間違ってますから。

「クラス型の変数をインスタンス化せずにそのprivateメンバにアクセスすること自体はできます。」

無理です。できません。
インタンス化していない以上非staticなメンバは存在していません。存在していないものにアクセスすることはできません。

カプセル化およびゲッター・セッターは必要なものでしょうか?

大規模なプログラムでは事実上必要です。

必要だとしたらあなたならどういった用途で使いますか?

外部からアクセスされたくない変数を誰かが間違ってアクセスして何かを破壊するというバグを減らすことに有効ですので、そのために使います。

また、そのクラスを使う人がアクセスする必要がない変数については取扱説明書に書く必要がないですね。ですのでドキュメントを減らすのにも有用です。

C++が初心者なので、他言語との違いを含めてアドバイスください。

なんのアドバイスが欲しいのでしょうか?
因みにカプセル化については、JavaやC#等多くのオブジェクト指向言語も同様です。この文脈では大差ありません。

大規模開発にカプセル化が必要だということですか?

その通りです。


【蛇足ですが】
「C++だとカプセル化ができますが、ゲッター、セッターを使わずにクラスのprivateメンバを直接、そのクラスのインスタンスから変更したり取得したりすることが可能です。」や「クラス型の変数をインスタンス化せずにそのprivateメンバにアクセスすること自体はできます。」について、aididaさんが本当に言いたいことが我々に伝わってきません。
前者はあまりにも当たり前過ぎます。「これはペンです」並のことしか言ってません。後者は明らかに間違いです。

しかし、日本語では曖昧でもプログラミング言語であれば厳密に表現できますから、具体的にコードを書いて頂ければ、伝わる可能性が高くなります。
「クラス型の変数をインスタンス化せずにそのprivateメンバにアクセスすること自体はできます。」について、何が可能なのか、実際にコンパイルに通るサンプル・コードを書いてみませんか?
その活動だけでも色々と明らかになることが出てくると思います。


【質問の追記に対する回答です】
まず、コードの提示、お疲れ様です。

インスタンス化=newすることのように理解されていたのですね。
そのクラスに記憶領域を割り当ててコンストラクタを呼び出すこと=インスタンス化です。
ですので、ローカル変数として割り当てる時もインスタンス化の1つです。

C++だとカプセル化ができますが、

ゲッター、セッターを使わずに
クラスのprivateメンバを直接、そのクラスのインスタンスから
変更したり取得したりすることが可能です。

ゲッター/セッターもメンバ関数ですから「そのクラスのインスタンスから」と同じものです。

カプセル化は情報の隠蔽とも呼ばれ、クラスの外部からアクセスする必要の無いメンバにアクセスできなくするという考え方です。C++はprivateメンバがそれに該当します。不用意に壊される心配がないので安心感がかなり出ます。
100行程度の小さなプログラムの時は鬱陶しいだけかも知れませんが、大きなプログラムで多くのメンバが関わる、長期間メンテナンスするような時はたいへんありがたい機能です。

もちろん、折角隠したメンバに対してゲッター/セッターを設けて全て公開するのは「愚か」な行為です。
外部I/Fは少ない方が頑健なプログラムになりますので、公開するメンバを無暗に増やさないことは重要なことです。

投稿2016/12/17 15:45

編集2016/12/18 15:07
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

クラスのprivateメンバを直接、そのクラスのインスタンスから変更したり取得したりすることが可能です。

「そのインスタンスのインスタンスメソッドから」であれば、それはある意味当然の機能です(「どこからも読み書きできない変数」なんて、存在しても全く無意味です)。ただ、「同じクラスの別なインスタンスの変数を動かせる」というのは言語によって異なってきます(Rubyでは、普通の方法では同じインスタンスのメンバ変数にしかアクセスできません)。

クラス型の変数をインスタンス化せずにそのprivateメンバにアクセスすること自体はできます。

これは確実に何かの勘違いです。なにせ、インスタンスが存在しなければ、ものが存在しない以上パブリックメンバへすらアクセスすることはできません。

ということで、前提段階で誤解だらけなので、まずはそのあたりの再確認からしていただければ幸いです。

(2016/12/18 17:38 追記)

C++の場合、newせずともオブジェクトが自動で生成して、参照を付け替えることもできない、というのは(他のオブジェクト指向言語にないので)逆に混乱するかもしれません。自分の場合、C++からオブジェクト指向に入ったために、JavaScript、Ruby、Javaなどで「オブジェクト型がすべて参照」ということに慣れなくて苦労した思い出はあります。

投稿2016/12/17 13:41

編集2016/12/18 08:41
maisumakun

総合スコア145123

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

「そのprivateメンバにアクセスすること自体はできます。」
↑これはクラス内からはアクセス出来る、ということですよね?

自分はほぼC++しかやってないので多言語と比較出来ませんが、C++では
そのように外部から見えないようにする(=カプセル化?)ことは、簡単に言えば
そのコードの利用者に利用法を”誤解させない”ことでバグの発生を防ぐ(誤った使い方をするとコンパイルエラー)
とかコードそのもので設計意図が分かるようにするとか、そういう効果です。
「動けばいい」という考え方であれば、ぶっちゃけカプセル化は不要ですねw

「ゲッター・セッター」というのはよく語られるので良いノウハウだと誤解されがちですが、
概念を抽象化してクラスを使う場合(よくある犬クラスとか)、ゲッター&セッターを使う必要が出て来るのは
設計ミスあるいは設計が破綻し始めている証拠です。
メンバの詳細を隠してクラスに全部任せようとしているのに(クラスの責任で細かいことをやってもらおうとしてるのに)、
「ゲッター・セッターで個別に読み書き出来たら意味ないじゃん」、ということです。
もしかしたらaididaさんもその辺がもやもやしてたのではないですか?

ゲッターのみならまだ書く場面はありますが、メンバに直接書くだけのセッターをあらゆるメンバ変数に
作り始めたら全く意味がないです。全部publicにするか、単なる構造体にした方がいいです。
C++初心者とのことなので、そこら辺はご自分が作りやすいように使えばいいのではないかと。

投稿2016/12/18 05:42

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

クラス型の変数をインスタンス化せずに
そのprivateメンバにアクセスすること自体はできます。

インスタンス化しないと、そのメンバは存在しないのでアクセスできません。
ただし、staticなメンバは実行開始直後に初期化されるので、そのクラス型の変数をインスタンス化に関係なく、アクセスできます。

ゲッター、セッターを使わずに
クラスのprivateメンバを直接、そのクラスのインスタンスから
変更したり取得したりすることが可能です。

もちろんできます。そのクラス自体から変更したり取得できなければ、一切アクセスが不可能になります。

他のクラスから勝手に変更したり取得できては困るメンバのゲッター、セッターをprotectedやpublicで定義しておき、他のクラスからの変更・取得はセッター・ゲッターを通じてのみ行うようにしておけば、メンバが保護されるのです。

例えば、メンバが1~12までの整数しか許容しない場合、他のクラスが仮に13を設定しようとセッターを呼び出せば、セッターはそれをエラーとして検出できます。そのメンバをpublicにしてしまうと、他のクラスが勝手に不正な値を設定できてしまいます。

また、複雑な過程を経てメンバの値が算出される場合、「このタイミングではまだ値が入っていないからアクセスしないでください」というルールを周知させることは難しいです。「どのタイミングならOKなんだ?」という苦情が他のクラスから来るかもしれません。「このゲッターを呼び出しさえすればどのタイミングでもOK」の方が簡単です。

自分のクラスは自分のメンバに自由にアクセスできますが、それは自分のクラスは自分のメンバの扱い方についてよく知っているはずなので、問題ありません。

メンテナンスでクラスの実装方法を変更することはとてもよくあります。メンバが追加されたり廃止されたり名前が変わったり役割が変わったり。クラスの全てのメンバのセッター・ゲッターを他のクラスに公開する必要はありません。出入り口すなわち限定されたセッター・ゲッターをさえ作っておけば、他のクラスからの利用方法が変わっても、内輪の事情が変わっても、コードの変更箇所を拡散させずに済むのです。

C++ではゲッター・セッターが関数呼び出し形式でしか提供できませんが、C#という言語ではゲッター・セッターがメンバ変数のようにアクセスできる「プロパティ」というものがあります。詳しい事は他の方に譲ります。

カプセル化の必要性は中規模開発で十分に感じます。

質問者さんに合わせて、メンバ変数のことを単に「メンバ」と呼びました。

投稿2016/12/17 15:01

naomi3

総合スコア1105

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ゲッター、セッターを使わずに

クラスのprivateメンバを直接、そのクラスのインスタンスから
変更したり取得したりすることが可能です。
クラス型の変数をインスタンス化せずに
そのprivateメンバにアクセスすること自体はできます。

何を言っているのかわからない。
詳しく頼む。

[追記] コードが示されたけど、

  • ゲッター、セッターを使わずにクラスのprivateメンバを直接、そのクラスのインスタンスから変更したり取得したりする
  • クラス型の変数をインスタンス化せずにそのprivateメンバにアクセスする

箇所はそれぞれどこですか?

投稿2016/12/17 13:24

編集2016/12/18 00:18
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aidida

2016/12/18 00:56

回答ありがとうございます。 ゲッター・セッターにを使わずについては、mainのs.b=2の行です。 クラス型の変数をインスタンス化せずに、mainのSample s;の行です。 s.b=2については、インスタンスだとしたらアクセスできるんじゃないかと 思ってました
episteme

2016/12/18 01:14 編集

> s.b=2については、インスタンスだとしたらアクセスできるんじゃないかと思ってました 思ってた、てことは"実際にはそうじゃなかった"てこと? だったら privateメンバを直接、そのクラスのインスタンスから変更/取得"できなかった"のね? とすると、ますますもって質問の意味がわからんです。真偽の定かでない前提に基づいた5つの質問にどうやって答えろと?
guest

0

まったく違いますね。

privateな メンバ ( メンバ変数, メンバ関数 ) へのアクセスは不可能です。

ソースコードにはかけますが、コンパイルが通りません。

自分が所属しているクラスオブジェクトのメンバへのアクセスや、クラスのメンバへのアクセスは可能です。
ですが、それ以外からはアクセス不可。

アクセス可能なら カプセル化の意味なし。

投稿2016/12/19 04:18

BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問