クラス継承時のメンバ変数の取り扱い

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
へろりくしょん

クラス継承時のメンバ変数の取り扱い

#1

投稿記事 by へろりくしょん » 15年前

いつもお世話になっております。

最近は今まで perl で書いていた使い捨てのプログラムをちこちこと勉強がてらC++で書くようにしているのですが、ちょっと分からないところがあり質問させていただきます。
class BASE{
protected:
    int a;
};

class HOGE : public BASE{
private:
    int b;
public:
    void func();
};

void HOGE::func()
{
    HOGE hoge;
    BASE base;

    hoge.b = 0;        //ok
    this->a = 0;    //ok
    base.a = 0;        //error
}

main(void)
{
    HOGE hoge;
    hoge.func();
}
上記のコードにて何故、base.a = 0; がエラーとなるのでしょうか。
そういう仕様だと言われればそれまでなのですが、どうにも納得がいきません。

またこういう場合はどのように記述するのが定石なのでしょうか。 クラス HOGE のメンバ関数 func() は他所からも自由に使える事を前提にお願いします。

初歩的な質問ですがよろしくお願いします。


#余談ですが、クラスのメンバ変数において、クラスの内側からは書き込み可、クラスの外側からは書き込み不可(どちらも読み取りは出来る)なアクセス指定子があったらいいなと思うのは私だけでしょうか。

dic

Re:クラス継承時のメンバ変数の取り扱い

#2

投稿記事 by dic » 15年前

#include <iostream>
using namespace std;

class BASE{
protected:
    int a;
public:
    void    SetValue( int val );
    int        GetValue();
};
void    BASE::SetValue( int val )
{
    a = val;
}
int        BASE::GetValue()
{
    return a;
}


class HOGE : public BASE{
private:
    int b;
public:
    void func();
};

void HOGE::func()
{
    HOGE hoge;
    BASE base;

    hoge.b = 0;        //ok
    this->a = 0;    //ok
//    base.a = 0;        //error
    base.SetValue(0);
}

void main(void)
{
    HOGE hoge;
    hoge.func();
}
ではどうでしょうか?

438番

Re:クラス継承時のメンバ変数の取り扱い

#3

投稿記事 by 438番 » 15年前

void HOGE::func()
はすでにHOGEクラスメンバ関数なので普通に変数を触れます
なので
HOGE hoge;
BASE base;
ともう一度してしまうと別にクラス型の変数を定義してそちらに代入しようとするので
protectedではエラーが出ます
(publicなら代入可能)

したいことと違っていたらすみません
一応ソース

class BASE{
protected:
int a;
};

class HOGE : public BASE{
private:
int b;
public:
void func();
};

void HOGE::func()
{
b = 0; //ok
  this->a = 0; //ok(thisは無くても)
a = 0; //ok

}

void main(void)
{
HOGE hoge;
hoge.func();

}

softya

Re:クラス継承時のメンバ変数の取り扱い

#4

投稿記事 by softya » 15年前

何がやりたいのでしょうか?
定義とインスタンスに対する操作がごっちゃになっているような?
HOGE::func()内部で、HOGE hoge;やBASE base;のインスタンスを作っているのは意味があるのでしょうか?
HOGE hoge;のインスタンスに操作してもメンバ関数func()を抜けるときにHOGE hoge;のインスタンスは消滅しますので操作した意味が無いことになります。
つまり、mainのHOGE hoge; と:func() 内の HOGE hoge;は別のインスタンスで別のメモリ空間を持つ別データとなります。

へろりくしょん

Re:クラス継承時のメンバ変数の取り扱い

#5

投稿記事 by へろりくしょん » 15年前

dicさん

>ではどうでしょうか?

これは私も考えました。
しかし、SetValue() GetValue() のようなメンバ関数を用意してしまうと、protected の意味が無いような気がするのですが。
メンバ変数 a のアクセス指定子に限らずフルアクセス出来てしまうということですよね。
クラスの仕様としてその手段を用意して上げるのはいささかどうかと思います。

実際には、GetValue() で返される値は変数 a のコピーですし、SetValue() では内部で assert を仕掛けることもできますので、多少は安全かなと思いますが、気休めのような気がしてならずちょっと敬遠してました。

やっぱりこうするのが一番なのでしょうか。


>438番さん

>ともう一度してしまうと別にクラス型の変数を定義してそちらに代入しようとするので
>protectedではエラーが出ます
>(publicなら代入可能)

とはどう解釈すればよいのでしょうか。

base.a = 0; と、インスタンス(base)を指定してますので、なんら混乱することなく代入は可能だと思うのですが。


追記です。

質問の趣旨は、クラス BASE から派生したクラス HOGE から基底クラスである BASE のメンバ変数 a へ this ポインタを経由すればアクセス出来るのに、他のインスタンスのメンバ変数 a へはアクセスできないのは何故か。 ということです。

よろしくお願いします。 画像

たかぎ

Re:クラス継承時のメンバ変数の取り扱い

#6

投稿記事 by たかぎ » 15年前

> 上記のコードにて何故、base.a = 0; がエラーとなるのでしょうか。
> そういう仕様だと言われればそれまでなのですが、どうにも納得がいきません。

そういう仕様です。
もし、base.a = 0; が可能なら、BASEを継承しさえすれば、全く関係のないところから自在にprotectedメンバにアクセスできてしまいます。
これではprotectedの意味がありません。

> #余談ですが、クラスのメンバ変数において、クラスの内側からは書き込み可、クラスの外側からは書き込み不可(どちらも読み取りは出来る)なアクセス指定子があったらいいなと思うのは私だけでしょうか。

そんなものはなくても、通常のメンバ関数(いわゆるgetter)で実現できます。

へろりくしょん

Re:クラス継承時のメンバ変数の取り扱い

#7

投稿記事 by へろりくしょん » 15年前

softyaさん

>何がやりたいのでしょうか?
>HOGE::func()内部で、HOGE hoge;やBASE base;のインスタンスを作っているのは意味があるのでしょうか?

クラス BASE は実際のところは抽象クラスであり、リスト構造になっていて、内部で生成・削除を行います。
HOGE::func()内で、クラス BASE のインスタンスを作っているのは、現在私が抱えている問題を分かりやすくするためです。

が、混乱を招いてしまったようで申し訳ありません。


たかぎさん

>そういう仕様です。
>もし、base.a = 0; が可能なら、BASEを継承しさえすれば、全く関係のないところから自在にprotectedメンバ>にアクセスできてしまいます。
>これではprotectedの意味がありません。

main() 関数から、クラス HOGE のメンバ変数 a にアクセス出来ないのは分かります。
しかし、HOGE::func() はクラス BASE を継承した クラス HOGE のメンバ関数です。
全く関係ないとは思えないのですが。 事実 this ポインタを経由すればアクセスできます。 これはどう解釈すればよろしいですか。

MNS

Re:クラス継承時のメンバ変数の取り扱い

#8

投稿記事 by MNS » 15年前

>事実 this ポインタを経由すればアクセスできます
thisの型はあくまでHOGE*でしょう。
確かに、HOGEのメンバ関数内であれば、
インスタンス化されたHOGEでも、変数aにアクセス可能です。
しかし、インスタンス化されたBASEでは別の話です。
たとえHOGEがBASEの派生クラスであろうと、
BASEのprotectedな変数であるaにはアクセス不可です。

たかぎ

Re:クラス継承時のメンバ変数の取り扱い

#9

投稿記事 by たかぎ » 15年前

> main() 関数から、クラス HOGE のメンバ変数 a にアクセス出来ないのは分かります。
> しかし、HOGE::func() はクラス BASE を継承した クラス HOGE のメンバ関数です。
> 全く関係ないとは思えないのですが。

同じクラスではないからです。
もし、異なるクラスでも、継承関係さえあればprotectedメンバにアクセスできるのであれば、

struct BAR : HOGE
{
static void func(HOGE& hoge);
};

とでもしておけば、BAR::funcを介して、HOGEクラスのメンバが触り放題になります。
しかも後付けで。
これはHOGEクラスの設計者の意図とは異なるはずです。

> 事実 this ポインタを経由すればアクセスできます。

同じクラスだからです。
同じクラスであれば、this経由でなくてもアクセス可能です。
例えば...


void HOGE::func()
{
HOGE hoge;
hoge.a = 0; //ok
}

となるはずです。

438番

Re:クラス継承時のメンバ変数の取り扱い

#10

投稿記事 by 438番 » 15年前

>どう解釈すればよいのでしょうか。

HOGE::func()はBASEクラスの派生クラスですので
hoge.a=0;
ならエラー無く通るはずです

>インスタンス(base)を指定してますので
こうしてみるとわかりやすいかもしれません

void HOGE::func()
{
  HOGE hoge;
BASE base;

  b=4;  //ok
hoge.b = 0; //ok
  this->a = 3; //ok
a = 0; //ok
  hoge.a=0;
  //base.a=0;エラーが出ます

  printf("b=%d\nhoge.b=%d\n",b,hoge.b);
  printf("hoge.a=%d\n",hoge.a);
  //printf("%d\n",base.a);エラーが出ます

}

実行結果
b=4;
hoge.b=0;
hoge.a=0;

インスタンスを作成したので
"b"と"hoge.b"は別物です
"a"というのはこのクラスの元となる"base"クラスが持つ変数ですので
アクセスが可能です
なので"a=0;"と代入が出来ます
(this.aというのはこれにあたります)

つまり今は
a, b  (もともとのクラスの変数)
hoge.a, hoge.b (インスタンスhogeの変数)
base.a (インスタンスbaseの変数)
があるわけです

base.aはクラスの外からアクセスしようとしているので
エラーが出ます
publicならアクセス可能なのでエラーが出ません

softya

Re:クラス継承時のメンバ変数の取り扱い

#11

投稿記事 by softya » 15年前

こうすると違うメモリ空間であることが実感できるかも。

hoge.b = 0; //ok
cout << &(hoge.b) << endl;
this->a = 0; //ok
cout << &(this->a) << endl;
a = 0; //
cout << &(a) << endl;
hoge.a = 0; //
cout << &(hoge.a) << endl;

this->aとaだけは同じメモリ空間(インスタンス)です。

へろりくしょん

Re:クラス継承時のメンバ変数の取り扱い

#12

投稿記事 by へろりくしょん » 15年前

MNS さん

>しかし、インスタンス化されたBASEでは別の話です。
>たとえHOGEがBASEの派生クラスであろうと、
>BASEのprotectedな変数であるaにはアクセス不可です。

そういう仕様なのですね。 
やっぱり納得はいきませんが、理解は出来ます。


たかぎさん

>とでもしておけば、BAR::funcを介して、HOGEクラスのメンバが触り放題になります。
>しかも後付けで。

これは確かに危険です。 アクセスレベルを解消するためだけに継承するという発想がありませんでした。

>となるはずです。

いや、も。 目から鱗です。 よくよく考えれば単純な話ですが、確かにその通りですね。


438番さん

>base.aはクラスの外からアクセスしようとしているので
>エラーが出ます

クラス BASE から継承したクラス HOGE もクラス BASE の外になるのですね。 それだと、クラス BASE から派生した クラス HOGE である this ポインタ(HOGE*)からもアクセス不可となるような気がするのですが。 ここがちょっと納得いかなかったのです。


softya さん

インスタンスが全くの別物だというのは分かっているのですが、thisポインタ(クラス BASEから継承した HOGE) からはアクセス出来るが、クラス HOGE 内で生成した別のインスタンス(クラス BASE)に、文法的にアクセス出来ないのは何でだろ? ということで質問させていただきました。



この件はこれで解決とさせていただきます。
回答してくださった皆様ありがとうございました。



忘れてました。 追記です。

たかぎさん

>そんなものはなくても、通常のメンバ関数(いわゆるgetter)で実現できます。

確かにその通りなのですが、メンバ変数が増えると、いちいち用意するのが面倒で。
あったらいーなーと思った次第です。
すみません。 ものぐさな人間なのです。 画像

へろりくしょん

Re:クラス継承時のメンバ変数の取り扱い

#13

投稿記事 by へろりくしょん » 15年前

すみません。 解決マーク入れ忘れてました。

閉鎖

“C言語何でも質問掲示板” へ戻る