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

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

ただいまの
回答率

90.48%

  • C++

    3592questions

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

クラスのメンバポインタ(?)について

解決済

回答 7

投稿

  • 評価
  • クリップ 1
  • VIEW 2,607

ristori

score 24

クラスについて質問です

class Product{
char *name;
int price;
}
としたときnameと*nameとどどちらがメンバなのでしょうか。

例えばこのクラスのオブジェクトproduct1に対してmain関数内で
char example='a';
product1.*name=  example;
としたときに、変数example自体はproduct1のメンバなのでしょうか。それともexampleのポインタのみがメンバですか?

そしてこのように、「ポインタをクラスのメンバ」にするような書き方は一般にするものですか?
そもそもポインタは変数ではないのでメンバという言い方はしないのでしょうか?

質問が多くてすいません。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 7

checkベストアンサー

+2

言語仕様として正しいかどうか自信はありませんが、回答してみます。


としたときnameと*nameとどどちらがメンバなのでしょうか。

nameがメンバー変数です。
char *namechar *型の変数と捉えたほうが分かりやすいと思います。


例えばこのクラスのオブジェクトproduct1に対してmain関数内で
char example='a';
product1.*name=  example;
としたときに、変数example自体はproduct1のメンバなのでしょうか。それともexampleのポインタのみがメンバですか?

メンバーというのは、クラスに所属している変数と関数のことですので、Productクラスのメンバーはnamepriceだけです。


そしてこのように、「ポインタをクラスのメンバ」にするような書き方は一般にするものですか?

一般的に良く使うと思います。と言っても、C++の場合はstringvectorのようにコンテナーの中にポインターを内包することが多いので、間接的に使うことが多いということになるのでしょうか。

ご質問の内容とは少しずれますが、もし文字列としてchar *を使うのであれば、動的に文字列のメモリーを確保することになります。その場合は、メモリーの割り当てと解放を自前で行う必要があります。解放は、クラスのデストラクタ―で行います。


そもそもポインタは変数ではないのでメンバという言い方はしないのでしょうか?

char *nameは、「char型のポインター」の変数です。
上で書いた通りで、これもメンバー変数です。

参考URL:
C/C++は永久に不滅です! - Part4 誰もがつまずくポインタを完璧理解:ITpro



(追記)

*product1.name= example;*は、ポインターの(アドレスに格納されている先の)値にアクセスする(演算を行う)、という意味なので、*product1.nameがメンバーかどうか、という問いをすることは無いと思います。

C/C++の場合、明示的にメモリーの解放(C++の場合はdeleteで行う)をしないと、すぐにエラーにはならず、メモリーリークという状態となってしまうので、特に注意が必要です。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/20 14:00

    解答ありがとうございます。
    メンバ変数となるのは
    「char型のポインター」の変数であるnameだけで、*name(内容はexampleのコピー)はメンバ変数ではない、ということですね。

    キャンセル

  • 2015/02/20 14:42

    追記しました。

    キャンセル

  • 2015/02/20 22:19

    詳しい解答ありがとうございます。ポインタの*は演算子という見方をするということですね

    キャンセル

+2

nameと*nameとどどちらがメンバなのでしょうか。
クラスのメンバ(変数)とは、その「変数名」のことを指します。この例ではnameがメンバ(変数)です。

としたときに、変数example自体はproduct1のメンバなのでしょうか。
それともexampleのポインタのみがメンバですか?
メンバ(変数)の前に、「クラス」と「インスタンス」の関係、「型」と「変数」の関係がごっちゃになっているようです。まずは簡単なint型のpriceメンバ変数で考えてみてください。
class Product { /*省略*/ };
Product product1;

int val = 100;
product1.price = val; 

- クラスProduct型の変数product1には、その値としてクラスProductから作り出したインスタンスが格納されています。
int型の変数valには、値100が格納されています。
procut1.priceは、変数product1に格納されたProduct型インスタンスの、int型のメンバ変数priceを表します。
product.price = val;とすると、変数product1に格納されたProduct型インスタンスの、int型のメンバ変数priceに、値100コピーされて代入されます。

// 質問文から転機したコード
char example = 'a';
product1.*name = example;
なお、質問文にあるコードではコンパイル時エラーになります。下記のように*を先頭に書く必要があります。(これでコンパイルは通るようになりますが、別の問題があるため実行時エラーになります。)
// 修正したコード
char example = 'a';
*product1.name = example;

そしてこのように、「ポインタをクラスのメンバ」にするような書き方は一般にするものですか?
一般的です。

そもそもポインタは変数ではないのでメンバという言い方はしないのでしょうか? 
ポインタは「型」です。「int型の変数」と同じように、「ポインタ型変数」という言い方をします。例えばint *p;は、「int型へのポインタ型(=int *型)の変数p」になります。先の例では、「クラスProductのメンバ変数priceは、char型へのポインタ型(=char *型)のメンバ変数」となります。


正しくは *product1.name= example; と書く必要があり、インスタンスを生成するときにnew、deleteで領域を確保しないとエラーがでてしまう

本質的な問題はproduct1.nameが有効なメモリを指していない、つまりポインタ型のメンバ変数nameを初期化していないことです。「インスタンスを生成するときにnew、deleteで領域を確保」は、初期化のための1つの手段です。(他の方法も考えられます)

*product1.nameはポインタ型変数が指す先を見に行く(参照はがし)操作ですが、product1.nameが有効なメモリ(変数)を指していない状態では、プログラムクラッシュなどの実行時エラーを引きおこしたり、全く無関係なメモリ(変数)に書き込んで値を破壊する不可解なバグの原因となります。


投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/20 13:56

    なるほど....
    ポインタは「整数型」などと同じように、型であるから、nameはポインタ型のメンバ変数ということですね。詳しい説明ありがとうございます。

    キャンセル

+2

>product1.*name= example;
>は正しくは
>*product1.name= example;
C,C++には便利な演算子がありまして、「ポインタ変数がクラスのメンバであり、その中身へとアクセスする場合」には、通常->演算子(アロー演算子)を使います。
exampleを代入する場合には下記のようになります。

product1->name = example;

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/24 22:39

    なるほど!ありがとうございます。

    キャンセル

+1

ポインタをクラスのメンバにすることはいたって普通に行う事です。そうでないとオブジェクト間の関連とか表現できませんから。
ちなみに、ポインタであるメンバにアクセスするときはアスタリスクは先頭に付けます。
char* example = "abc";
product1.name = example;
char c = *product1.name;
あと、下記はproduct1.nameが指す領域が確保されていないので、実行時エラーになるはずです。。
char example = ’a’;
*product1.name = example;

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/20 13:57

    ありがとうございます。

    キャンセル

+1

この場合のメンバ変数になるのは
>「char型のポインタ型」の変数nameであり、その内容(char型の変数)*nameはメンバ変数ではない、と理解致しました。
「メンバ変数nameはcharポインタ型である。」
ここまではあっています。

「その内容(char型の変数)*nameはメンバ変数ではない」
上記についてですが、「*name」はchar型の変数ではありません。
「charポインタ型の変数nameの中身を参照する」という操作です。

ポインタの中身を参照するために変数の前につける"*"と、変数宣言時の"*"の部分で混乱してそうですね。


ちなみに、多くの教科書でポインタの宣言は「char *name;」というような記載になっていますが、上記のような誤解を招きやすいので「char* name;」と宣言することをお勧めします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/24 22:38

    *はcharポインタ型の変数nameの中身を参照する演算子、という解釈でよろしいでしょうか。おっしゃる通り混乱していました。

    キャンセル

  • 2015/02/25 09:00

    その認識で合ってます。
    ここ、混乱しやすいですよね…

    キャンセル

+1

exampleをnameへ代入する場合、
1. nameのメモリー領域を確保。
2. exampleの内容(この場合、'a')をnameにコピー。
3. nameを使わなくなったら、メモリーを開放(デストラクタなどで)。
の手順になります。
1.2.を行うことで、exampleの実体が無くなっても(exampleがローカル変数で、サブルーチンから抜けるなどでスコープから外れても)、Productのインスタンスがある限り、nameが値を保持しています。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/24 22:42

    nameはアドレスだと思うのですがexampleはインスタンスのどこにコピーされますか??

    キャンセル

  • 2015/02/24 23:18

    例えば、Productクラスは以下のような形になると思います。
    nameへは、ゲッター、セッターを通してアクセスします。

    exampleの値を代入するためには、セッターを使います。
    product1.setName(exmple)
    セッターの中では、
    nameのメモリ領域を確保し、
    *name = example
    を行っています。

    class Product {
    public:
    // コンストラクタ
    Product() : name_(0), price_(0) {};
    // デストラクタ
    ~Product() {
    if (name_) {
    delete name_;
    name_ = 0;
    }
    };
    // name_ のゲッター
    char name() const { return *name_; };
    // name のセッター
    void setName(char name) {
    if (name_) {
    delete name_;
    name_ = 0;
    }
    name_ = new char;
    *name_ = name;
    };
    private:
    char* name_;
    int price_;
    };

    キャンセル

  • 2015/02/25 23:03

    詳しい説明ありがとうございます。

    キャンセル

+1

様々な方が意見していただいているので補足だけ。
そしてこのように、「ポインタをクラスのメンバ」にするような書き方は一般にするものですか? 
一般的な理由をあげると、クラスのメンバ変数にしない場合、外部からアクセス可能になり様々なトラブルの原因となります。(ポインタのアドレスを変更した:newで動的確保した場合deleteできないなど)
ポインタを直接扱える状態にすることはC++の思想から好ましくありません。
複数人での開発を考えると、privateで保護することが望ましいでしょう。
インスタンスを生成するときにnew、deleteで領域を確保しないとエラーがでてしまう
newで動的確保する理由は
  1.  値を代入できる領域の確保
  2.  入ってくるデータ量が不定(バッファオーバーフロー対策)
  3.  必要な分だけの領域を使用する(文字列など1文字から不定)
などが挙げられます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/26 23:51

    なるほどよくわかりました。ありがとうございます

    キャンセル

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

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

関連した質問

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

  • C++

    3592questions

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