みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

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では何がいけないのでしょうか?

以上、よろしくお願いします。

投稿日時 - 2007-02-24 18:01:11

QNo.2780570

困ってます

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

> なぜこんな面倒な事をしないといけないのかが分かりません。

配列の実体の定義をひとつにするためです。

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言語と同様にリンクエラーとなってしまうでしょう。
それならば、コンパイルも通さないほうが親切です。
ということで、最初のコードは通らないように規格が制定されたのでしょう。

なぜ、リンクエラーを起こすようになっているのかは、処理が複雑になり過ぎるためです。
コンパイル・リンク時間の増大やコンパイラ・リンカの不具合など、デメリットが大きすぎるんですね。

ちなみに、整数定数などは宣言と定義を同時にできますが、
これはサイズが小さく実体を複数作っても問題がないため、インライン展開や多重定義自体を許可することで実現しています。

投稿日時 - 2007-02-27 04:11:35

お礼

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

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

ありがとうございました。

投稿日時 - 2007-03-02 23:27:14

ANo.3

このQ&Aは役に立ちましたか?

5人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.2

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

投稿日時 - 2007-02-26 02:40:17

お礼

ありがとうございます。

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

投稿日時 - 2007-03-02 23:28:40

ANo.1

# 動作は仕様通り、(少なくとも現行仕様の範囲では)そういうものです>C++

> コード1では何がいけないのでしょうか?

言語仕様にそれを許可する記述がないから。

> こうすればコンパイルが通る事は分かったのですが、
> なぜこんな面倒な事をしないといけないのかが分かりません。

そういう言語仕様だから、ですかね。
ISO/IEC14882:2003 9.4.2 Static data membersあたりをご覧ください。

元々、整数定数などが宣言と定義を一緒にできるのは、
利便性のために、明示的にそれを許可する規定が盛り込まれたためです。
配列はここに規定されてません(許可されてるものの方が少ないです)。

# そもそも言語仕様Fix前のVC6みたいな古いコンパイラは、整数でも通らない…。

投稿日時 - 2007-02-24 18:54:54

お礼

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

投稿日時 - 2007-03-02 23:29:19