アプリケーション開発ポータルサイト
ServerNote.NET
ServerNote.NET厳選キャンペーン・クーポンはこちら!
カテゴリー【C/C++
【C++】staticメンバ変数がundefined referenceとエラーになる場合
POSTED BY
2022-09-15

クラスが生成される度にインクリメントしてクラス番号を付与する目的で、staticなメンバ変数を以下のように宣言して使うとする。

C/C++static_error.cppGitHub Source
#include <iostream>

class Test {
public:
  static int sSequence;
  int mClassNo;
  Test(void);
  ~Test(void);
};

Test::Test(void) {
  mClassNo = sSequence++; //自分のクラス番号をスタティックシーケンスから付与し、シーケンスを加算する
}

Test::~Test(void) {

}

int main(void) {
  Test t1 = Test();
  Test t2 = Test();

  std::cout << "t1 no=" << t1.mClassNo << ",t2 no=" << t2.mClassNo << ",sequence=" << Test::sSequence << std::endl;

  return 0;
}

コンストラクタでクラス番号を付与しstaticシーケンスを加算、mainで2つクラスを生成し番号を出力する単純なものだが、これをコンパイルすると以下リンクエラーになる。

g++ static_error.cpp

/tmp/cc7lZydV.o: In function `Test::Test()':
static.cpp:(.text+0xa): undefined reference to `Test::sSequence'
static.cpp:(.text+0x13): undefined reference to `Test::sSequence'
/tmp/cc7lZydV.o: In function `main':
static.cpp:(.text+0x52): undefined reference to `Test::sSequence'
collect2: error: ld returned 1 exit status

sSequenceなんてものは無いと言われておかしいな??と思ったがstaticメンバ変数はメンバ関数と同様、明示的に定義する必要があった。
つまりコンストラクタの前あたりで、以下のように明示的に定義と初期化を行う。

C/C++static_success.cppGitHub Source
#include <iostream>

class Test {
public:
  static int sSequence;
  int mClassNo;
  Test(void);
  ~Test(void);
};

int Test::sSequence = 0;

Test::Test(void) {
  mClassNo = sSequence++; //自分のクラス番号をスタティックシーケンスから付与し、シーケンスを更新する
}

Test::~Test(void) {

}

int main(void) {
  Test t1 = Test();
  Test t2 = Test();

  std::cout << "t1 no=" << t1.mClassNo << ",t2 no=" << t2.mClassNo << ",sequence=" << Test::sSequence << std::endl;

  return 0;
}

g++ static_success.cpp

./a.out
t1 no=0,t2 no=1,sequence=2

今度はちゃんとコンパイル・リンクが通り、期待通りの実行結果になった。

int Test::sSequence = 0;

とするのがポイントで、

static int Test::sSequence = 0;

などとしてしまうと、ファイル内staticと勘違いされてエラーになる。

また、Javaのようにヘッダのクラス宣言時に初期化してしまえばいいではないかと思いがちだが(以下)、

class Test {
public:
  static int sSequence = 0;

これは今度は

static_error.cpp:5:25: error: ISO C++ forbids in-class initialization of non-const static member ‘Test::sSequence’

などと言われ結局エラーになるので注意。

staticでない変数(上記だとmClassNo)は定義の必要は無く、コンストラクタで初期化すればいい。

1台4役!スマホとWi-Fiが1台に【X-mobile スマートWiFi】
「1つを選ぶ時代は終わった!」で始まる、氷川きよしさんをイメージキャラクターに起用し CM配信中のエック...READ MORE
髪質改善・美髪ケア【ミネコラ パーフェクト3】雑誌多数掲載!
ミネコラは、《水素》で髪が蘇る究極のエイジングヘアケア。 「ミネコラ パーフェクト3」は水素サロンケア...READ MORE
こころも安らぐ上質なバスタイムを。アメリカ生まれのエプソムソルト「ティールズ」
【Dr.Teal's(日本名:ティールズ)】は バスケアカテゴリーにおいて6年連続で全米売上NO.1を取得しています...READ MORE
※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
【webmaster/管理人】
自営業プログラマー
ご連絡は以下アドレスまで★

☆ServerNote.NETショッピング↓
ShoppingNote
☆お仲間ブログ↓
一人社長の不動産業務日誌
【キーワード検索】