ページ 11

継承を避けたとき、クラス内での定数の扱い

Posted: 2011年9月03日(土) 16:13
by paw
このサイトのSNSコンテンツの方で、日記にて継承についての質問をさせていただいた者です。
質問するときは掲示板を使うべきという事で、改めて掲示板にて質問させていただきます。
日記の方で、アドバイス、回答をしていただいた方ありがとうございました。

本題ですが、
継承は極力避けるべきだとの意見を頂きました。
継承を使いすぎるとクラス関係がグチャグチャになるので、ということだと解釈しました。

そこで継承を使わずに実装しようとしたところで、メンバ変数の指定子をprotectedにしたときのようなことができないという事に気づきました。
その疑問点を再度質問させていただいたところ、うまく設計していたらprotectedを使わずとも、ゲッターセッターで十分な量に収まるという回答を頂きました。

ここで、新たに疑問が沸きました
クラス内での定数、これを結構使っていたのですが、protectedメンバでの継承を使わなければ、これも、継承を使った時の子クラスに相当するクラスでは使えませんよね。
定数なのでゲッターでの代入も出来ません。

例えば・・・

コード:


#include <iostream>
using namespace std;

class Super{
private:
	static const int MAX = 10;
	static const int MIN = 0;
	int data;

public:
	Super(){}
	int Getter_Data(){
		return data;
	}

	int Getter_MAX(){
		return MAX;
	}
};


class Sub{
private:
	Super ObjSuper;
	int get_data;
	static const int get_MAX;
public:
	void GetSuperData(){
		get_data = ObjSuper.Getter_Data();
		get_MAX  = ObjSuper.Getter_MAX(); //エラー
	}
};
もちろん定数に値を代入できるはずもありません。
こういう時はどうされているのでしょうか?
どうするのがいいのでしょうか?

Re: 継承を避けたとき、クラス内での定数の扱い

Posted: 2011年9月03日(土) 19:28
by うしお
コンポジションの場合の定数ですが、
わざわざSub側でstatic const で値を保持する意味は無いと思うのですがどうでしょう?
単純にObjSuper.Getter_MAX();で事足りると思います。(取得するデータが大きくてコピーはあまりしたくないなら分かりますが)

また定数メンバの場合はゲッターを用意する意味は無いと思います。
不変ですから、不正な値に変化させられることは無いですし、
マルチスレッドを考えたとしても、定数メンバは本質的にスレッドセーフです。

必要であれば静的定数メンバはpublicにしましょう。
どうしてもアクセスに疑問を感じるのであれば、本当にその定数はそのクラスに持たせるべきか疑ってみましょう。

例えばこういうのはどうでしょう

コード:

class Super
{
public:
	Super():m_data(0){}

	int getData()const
	{
		return m_data;
	}

  static const int MAX;
  static const int MIN;
private:
	int m_data;
};
const int Super::MIN = 0;
const int Super::MAX = 10;

class Sub
{
public:
	Sub():m_super(){}

	void hoge()const
	{
		int data = m_super.getData();
		const int min = Super::MIN;
		const int max = Super::MAX;
	}
private:
	Super m_super;
};

Re: 継承を避けたとき、クラス内での定数の扱い

Posted: 2011年9月03日(土) 21:03
by paw
メンバ変数は全部privateにしなければならないと思い込んでいました。
ありがとうございます。非常に参考になりました。

>>例えばこういうのはどうでしょう
普通にstatic const int~ のprivateをpublicにしただけのものではいけないのでしょうか?

コード:

#include <iostream>
using namespace std;
 
class Super{
private:
    int data;
 
public:
    Super(){}
    int Getter_Data(){
        return data;
    }
    static const int MAX = 10;
    static const int MIN = 0;

};
 
 
class Sub{
private:
    Super ObjSuper;
    int get_data;
    static const int get_MAX;
public:
	Sub();
    void GetSuperData(){
        get_data = ObjSuper.Getter_Data();
		cout << ObjSuper.MAX << endl;
    }
};

int main(){
	Sub ObjSub;
	ObjSub.GetSuperData();
return 0;
}
もうひとつ、関係のないことですが、
Super():m_data(0){}
これは、何をしているんでしょう?
そもそもこういう形を見たことが無い上に、継承でもないのに「:」を使っているのが気になったのですが・・・

Re: 継承を避けたとき、クラス内での定数の扱い

Posted: 2011年9月03日(土) 21:43
by h2so5
paw さんが書きました: もうひとつ、関係のないことですが、
Super():m_data(0){}
これは、何をしているんでしょう?
そもそもこういう形を見たことが無い上に、継承でもないのに「:」を使っているのが気になったのですが・・・
「C++ 初期化リスト」で調べてみてください。

Re: 継承を避けたとき、クラス内での定数の扱い

Posted: 2011年9月04日(日) 00:33
by paw
ありがとうございます。
大体わかりました。

他やり方は同じようなので解決とさせていただきます。
答えて下さった方ありがとうございました。