• ベストアンサー

static constメンバ変数(配列)の初期化について

C++初心者です。 constメンバ変数の初期化について教えてください。 クラスの中に、static constメンバ変数(配列)を持ちたいのですが、 <コード1> class hoge { public : hoge(){}; virtual ~hoge(){}; static const int fuga[2] = {1, 2}; }; とすると、VC++ 2005では、 error C2059: 構文エラー : '{' error C2334: '{' の前に予期しないトークンがありました。関数の本体は無視されます というエラーが発生します。 何がいけないのでしょうか? また、下の様にするとOKでした。 <コード2> class hoge { public : hoge(){}; virtual ~hoge(){}; static const int fuga[2]; }; const int hoge::fuga[2] = {1,2}; こうすればコンパイルが通る事は分かったのですが、なぜこんな面倒な事をしないといけないのかが分かりません。 コード1では何がいけないのでしょうか? 以上、よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • 1839cc
  • ベストアンサー率54% (12/22)
回答No.3

> なぜこんな面倒な事をしないといけないのかが分かりません。 配列の実体の定義をひとつにするためです。 C++言語はC言語のスーパーセットですから、C言語とほぼ同様の特性を持っています。 この問題はC言語の知識があれば直感的に理解できるでしょう。 類似コードをC言語で書くと以下のようになります。 (もう、C言語は自信ないですが・・・) [hoge.h] typedef struct tagHoge { /* メンバ */ } Hoge; extern const int hoge_fuga[]; void hoge_initialize(Hoge*); void hoge_finalize(Hoge*); [EOF] [hoge.c] const int hoge_fuga[] = {1, 2}; void hoge_initialize(Hoge*) {} void hoge_finalize(Hoge*) {} [EOF] このコードは、extern で hoge_fuga という配列を外部参照し、 hoge.c ファイル中でその実態を定義するという単純なコードです。 hoge.c 以外のソースファイルで hoge_fuga の実体を定義すると多重定義でリンクエラーが起きてしまいます。 ですので、hoge.h をインクルードすることで外部参照宣言のみを行います。 もし質問者さんの最初のコードでコンパイルが通るとした場合、 hoge::fuga の実体は複数のソースファイルで定義されてしまう可能性が出てしまいますので、 その場合はC言語と同様にリンクエラーとなってしまうでしょう。 それならば、コンパイルも通さないほうが親切です。 ということで、最初のコードは通らないように規格が制定されたのでしょう。 なぜ、リンクエラーを起こすようになっているのかは、処理が複雑になり過ぎるためです。 コンパイル・リンク時間の増大やコンパイラ・リンカの不具合など、デメリットが大きすぎるんですね。 ちなみに、整数定数などは宣言と定義を同時にできますが、 これはサイズが小さく実体を複数作っても問題がないため、インライン展開や多重定義自体を許可することで実現しています。

fugafugahogehoge
質問者

お礼

なるほど。 ありがとうございます。 頂いた回答を見ていて、また疑問に思う事がありましたので、ちょっと試してみて、それから改めて質問したいと思います。 ありがとうございました。

その他の回答 (2)

  • koedame
  • ベストアンサー率33% (10/30)
回答No.2

まあ、私もよくはわからないけど、 通常のメンバ変数もクラスの定義内では初期化できないから。 恐らく同じ原理なのではないですか。 ・・・多分。

fugafugahogehoge
質問者

お礼

ありがとうございます。 でも、static型なので、 >通常のメンバ変数もクラスの定義内では初期化できないから。 >恐らく同じ原理なのではないですか。 という訳ではなさそうです。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.1

# 動作は仕様通り、(少なくとも現行仕様の範囲では)そういうものです>C++ > コード1では何がいけないのでしょうか? 言語仕様にそれを許可する記述がないから。 > こうすればコンパイルが通る事は分かったのですが、 > なぜこんな面倒な事をしないといけないのかが分かりません。 そういう言語仕様だから、ですかね。 ISO/IEC14882:2003 9.4.2 Static data membersあたりをご覧ください。 元々、整数定数などが宣言と定義を一緒にできるのは、 利便性のために、明示的にそれを許可する規定が盛り込まれたためです。 配列はここに規定されてません(許可されてるものの方が少ないです)。 # そもそも言語仕様Fix前のVC6みたいな古いコンパイラは、整数でも通らない…。

fugafugahogehoge
質問者

お礼

なるほど。仕様ですか。 ありがとうございます。

関連するQ&A

  • メンバ変数が変更されそうなconstメンバ関数

    c++のconstメンバ関数についての質問です。 以下のコードの様に、constメンバ関数で メンバ変数を変更しているように見える場合、 本来はどのように記述すべきか? class foo { public: foo(){} foo(int i){ d = i; } void hoge(foo *dest0, foo *dest1 ) const { dest0->d = d*2; dest1->d = d*4; } int d; }; int main() { foo f(1); foo p,q; f.hoge(&p,&q); std::cout << f.d << "\n"; std::cout << p.d << "\n"; std::cout << q.d << "\n"; f.hoge(&f,&q); std::cout << f.d << "\n"; std::cout << q.d << "\n"; return 0; } ちなみに出力期待値は 1 2 4 2 4 とします。 上のコードは 1 2 3 2 8 と出力されますが、このようなことが無いように実装するには どうすべきかという質問です。 dest0->d = d*2; dest1->d = d*4; の所を int i=d; dest0->d = i*2; dest1->d = i*4; とすべき? それともhogeの最初に if( (this == dest0) || (this == dest1) || (dest0== dest1) ){ throw "同じオブジェクトじゃだめ"; } とすべき? どんな書き方が安定でしょうか?

  • 文字列のメンバ変数を外部変数のように扱いたい

    済みません。質問なのですが、 メンバ変数を外部変数のように扱うにはどうしたらよいのでしょうか? int型などの場合、 class test{ static const int a; }; const int test::a = 10; とすればよいですよね? これをcharの配列にして class test{ static char a[7][32]; }; char test::a[0] = "test"; とすると サイズが0の配列を割り当てまたは宣言しようとしました というコンパイルエラーがでてしまいます…。 多次元配列の場合はstatic変数としてもてないのでしょうか? char** として宣言してもどこでnewを行えばよいか解りません。 コンストラクタの中で行えば そこでstaticではなくなってしまいますし…。 後、できればstringクラスの配列で持ちたいのですが #include <string> class test{ static string test[7]; }; string test::test[0] = "aaa"; なんてことができますでしょうか? 質問内容が解りにくいかも知れませんが どうか教えてください。 宜しくお願いいたします。

  • constのついたメンバ関数

     こんにちは。 C++を勉強しているのですが疑問に思ったことがあります。 const指定したメンバ関数にメンバ変数の変更をすることはエラーになるはずなんですが、 下記にある(*m_pRefCnt)++; はコンパイルが通るようです。 なぜこの一文だけ通るのでしょうか? 以下にソースを添付しておきます。 #include <iostream> class hogeClass { private: int* m_pRefCnt; int val; void AddRef() const { (*m_pRefCnt)++; // これはOK? val = 100; // これは駄目 } void Release() { } public: explicit hogeClass(char* src = NULL) : val(0) { } int& GetRefCnt() { return *(m_pRefCnt); } virtual ~hogeClass() { Release(); } }; int main() { int c = 435, k = 222; using namespace std; hogeClass a; getchar(); return 0; } 分かる人がいたらよろしくお願いします。

  • const参照メンバを含む要素のvector

    久しぶりに趣味でプログラミングしてます。 const参照のメンバを含むオブジェクトを要素に持つvector って使えます? 下記はbcc32でコンパイルするとエラーが出ます。 _algobase.h 145:コンパイラは 'operator=' クラスの hoge を作成できない(関数 _STL::hoge * __copy<hoge *,hoge *,int>(hoge *,hoge *,hoge *,const random_access_iterator_tag &,int *) ) ちなみにv.clear();をコメントアウトするとコンパイルは通り実行も問題なくできます。 clear()の替わりにpop_back()としてもコンパイルは通り実行も問題なくできます。 コンパイラーのバグ?そもそもこんなことをしてはダメ? よろしくお願いします。 class hoge { public:  hoge(const int &i):_i(i){};  virtual ~hoge(){};  operator int () const {return _i;}  const int &_i; }; int main() {  int i1=1;  int i2=2;  hoge h1(i1);  hoge h2(i2);  std::vector<hoge > v;  v.push_back(h1);  v.push_back(h2);  v.clear();  std::vector<hoge >::iterator iter = v.begin();  while( iter != v.end() ){   std::cout << *iter << "\n";   ++iter;  }  return 0; }

  • static 変数について

    static 変数について 今、C++を勉強しているのですか、static変数がどのように動くのかよくわかりません。 下のプログラムのint a はローカル変数だから、ブロックを抜けたら、初期化されるためstatic変数にして、ブロックを抜けても値を保持するようにすってことはわかるのですが 毎回このブロックに入る度、static int a = 0;を読むことになり、その前に入っていた値はなくなるのではないでしょうか?それとも,static int a と書かれていると,1度しか実行されないから、値が保持され続けるのでしょうか? int add (int x ) { int a = 0; a += x; return a; }

  • Python のクラスのメンバ変数

    class foo( object ):        __result = []        def __init__( self, n, m ):       # self.__result = []       self.__result.append( n + m )    def func( self ):       print self.__result[0] hoge = foo( 1, 2 ) fuga = foo( 3, 4 ) hoge.func() # 3 fuga.func() # 3 ... !? 数値や文字列といったメンバ変数は、コンストラクタで意図的に初期化してやらなくても正常な値になりますが、それ以外のオブジェクトや配列だと fuga は hoge のメンバと同じものになってしまいます。他の言語の感覚ですと、__result は foo のメンバな上にプライベートなので、fuga の __result が hoge.__result を指すのは考えられない事なのですが、この書き方がマズいのでしょうか。 また、もしこのようになっている理由等もありましたら、併せてお教えください。

  • const int&の戻り値について

    const int&の戻り値について c++で「const int&(const int a)const{...」についてのメンバ関数がありますが、そのconst int&はどういう意図に使われるのでしょうか。 &があるので、アドレスを返すと思いますので、ポインタ変数に入れるだけでしょうか。それでもポインタ変数とメンバ関数の戻り値のアドレスは違うのはどういうことでしょうか。 主な使い用途がありましたら、教えてください。

  • メンバ関数にconstをつけた際の問題

    C++を勉強中の学生です。 以下のようなコードで問題が起こりました。 class TEST{ private: int mArray[10]; //(int a;) public: int* get_mArray(void) const; //(int get_a(void) const;) }; int* TEST::get_mArray(void) const{ return mArray;    //配列の先頭要素の値を受け取りたい。 } //(関係のありそうな部分のみを抜き出しました) このコードにおいて、関数は値を変えない事が明白なので、constをつける必要性はないのですが(癖でつけた際に発生した問題です)、 なぜconstをつけると動作しなくなるのか知りたいです。 //()で囲った部分を有効にし、 int TEST::get_a(void) const{return a;}という関数はエラーにならなかったのですが、どのような違いがあるのでしょうか? 出たエラーは(visual C++ 2010) 'const int [10]' から 'int *' に変換できません。 というものでした。 ポインタとconst関連の部分を手持ちの本で勉強しなおしたのですが、解答を得られなかったのでこちらで質問させてもらいます。

  • ヘッダーファイル内でconst変数を初期化する時にエラー

    ヘッダーファイル内でconst変数を初期化する場合、 以下のようにしているのですが、エラーが出てしまいます。 どのようにすればうまくいくのでしょうか? 環境はVisualC++.NETです。 class abc{ private:  const int x; public:  abc(){   x = 10;  } }

  • クラス内の関数内static変数について

    クラス内の「staticではないメンバ関数内で定義される」static変数の初期化タイミングはいつでしょうか? 自分としてはクラスのインスタンス生成時に初期化されるものだと思っていたのですが、どうもそうでは無さそうだという現象に出会ったもので。 例えば以下のようなサンプルプログラムがあるとします。 --------------------------------------- class TA { public: void func(int i); }; void TA::func(int i) { static int d=0; d += i; std::cout << d << std::endl; } int main() { for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); } } --------------------------------------- これを実行した時、自分としては 1 2 3 2 4 6 という結果を期待していた訳ですが、実際には 1 2 3 5 7 9 という結果になりました。 ということは、もしかしてメンバ変数ではなくともクラス内に現れるstatic変数はstaticなメンバ変数と同等ということなのでしょうか? 実際、上記ソースのforループ内にもう一つclass TAのインスタンスtbを追加してみると、 --------------------------------------- for(int i=1; i < 3;i++) { TA ta; ta.func(i); ta.func(i); ta.func(i); TA tb; tb.func(i); tb.func(i); tb.func(i); } --------------------------------------- 1 2 3 4 5 6 8 10 12 14 16 18 となりました。 (まぁstaticではないメンバ変数に置き換えれば一応解決するのですが、個人的に何か凄く気持ち悪く感じて・・・)

専門家に質問してみよう