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

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

ただいまの
回答率

87.78%

C++ カプセル化のこと

受付中

回答 6

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 4,032

score 14

こんにちは。

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

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

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

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

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

よろしくお願いしますー

**Sample.h**

#ifndef _SAMPLE_H_
#define _SAMPLE_H_

class Sample{
public:
    int a;      //  publicなメンバ変数
private:
    int b;      //  privateなメンバ変数
public:
    void func1();
private:
    void func2();
};

#endif // _SAMPLE_H_
**Sample.cpp**

#include "Sample.h"
#include <iostream>

using namespace std;

void Sample::func1(){
    cout << "func1" << endl;
    a = 1;
    b = 1;
    func2();                    //  func2ないから、func1を呼び出す
}
void Sample::func2(){
    a = 2;
    b = 2;
    cout << "a=" << a  << "," << "b=" << b << endl;
}
**main.cpp**

#include "Sample.h"
#include <iostream>

using namespace std;

int main(){
    Sample s;//←このsがインスタンス化されてないものと思ってました
    s.a = 1;
    //s.b = 2;
    s.func1();
    //s.func2();
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • KSwordOfHaste

    2016/12/17 22:33 編集

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

    キャンセル

  • KSwordOfHaste

    2016/12/18 10:19

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

    キャンセル

回答 6

+5

こんにちは。

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

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

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

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

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

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

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

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

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

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

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

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

その通りです。


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

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


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

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

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

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

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

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

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/18 09:56

    回答ありがとうございます。
    ゲッター・セッターにを使わずについては、mainのs.b=2の行です。
    クラス型の変数をインスタンス化せずに、mainのSample s;の行です。

    s.b=2については、インスタンスだとしたらアクセスできるんじゃないかと
    思ってました

    キャンセル

  • 2016/12/18 10:08 編集

    > s.b=2については、インスタンスだとしたらアクセスできるんじゃないかと思ってました

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

    キャンセル

+1

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

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

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

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

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

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

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

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

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

まったく違いますね。

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 87.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る