- ベストアンサー
namespace定義の使い方
こんにちは。 C++を勉強しています。 今回は、namespace宣言して使いたいのですが、ヘッダー内でnamespace宣言をすると重複してしまいます。namespaceで定義したものを他のファイルでも使いたい場合はどうすればいいでしょうか? よろしくお願いします。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
ヘッダファイルの2重読み込みではなく、ヘッダファイルで(宣言でなく)定義をしてしまったというケースでしたか。 この場合、2つの方法があります。 1.ヘッダファイルでは宣言だけを行い、ひとつの実行ファイル(のみ)で定義を行う ------- test.h ------ namespace TEST_SAPCE { extern int d; // ここは宣言 extern short h; } ------- test.cpp ------- #include "test.h" int TEST_SAPCE::d; // ここで定義 short TEST_SAPCE::h; int main() { TEST_SAPCE::d = 1; TEST_SAPCE::h = 0; return 0; } ------- sub.cpp ------- #include "test.h" void sub() { TEST_SAPCE::d = 1; TEST_SAPCE::h = 0; } 2.インクルードファイルでマクロを使い、定義と宣言を切り分ける方法 ------- test.h ------ #if defined(GLOBAL_HERE) #define GLOBAL #define init(x) = (x) #else #define GLOBAL extern #define init(x) namespace TEST_SAPCE { GLOBAL int d; GLOBAL short h init(10); } ------- test.cpp ----- // ひとつの実行ファイルだけ、test.h をinclude する前に、GLOBAL_HERE を定義する #define GLOBAL_HERE #inlcude "test.h" int main() { TEST_SAPCE::d = 1; TEST_SAPCE::h = 0; return 0; } ------- sub.cpp ------- #include "test.h" void sub() { TEST_SAPCE::d = 1; TEST_SAPCE::h = 0; }
その他の回答 (5)
- sygh
- ベストアンサー率76% (42/55)
Visual C++限定で良いのであれば、 namespace Test { __declspec(selectany) int g_variableName; } のようにしてしまえばインスタンス生成が1回だけ行なわれるようになるので、ヘッダに宣言(Declaration)と定義(Definition)をまとめて記述できちゃいますが、それ以外のコンパイラの場合は他の回答者の方々が例示してらっしゃるように、ヘッダ側に宣言を記述(公開)して、ソースファイル側に実体を定義(実装)するようにします。 ただC++ではグローバル変数なんぞ使わないほうが無難です。 最悪でもstaticメンバーを使ってシングルトン実装にするのが定石かと。 ちなみに変数でなくconstを付けた定数であれば、C++の場合デフォルトで内部リンケージなので、ヘッダでも宣言と定義を記述できるようになっています。これにより、C言語でよく使われていたマクロ定数がほとんどの場面で不要になります。 namespace Test { const double PI = 3.141592653589793238; }
お礼
constを付けた場合だと重複定義にならないんですね。 参考書でconstを勧める意味が分かりました。
- Tacosan
- ベストアンサー率23% (3656/15482)
既に答は出てるから蛇足だけど, 名前空間内だからといって特別なことはないんだよね. ヘッダで int x; とかやったらダメというのはいいよね? namespace で囲まれてるけど, 基本的にはこれと同じこと. 無名名前空間だとヘッダで定義しても二重定義にならないから話は違うけど, それで何を期待するのかはやっぱりわからん.
お礼
namespaceで括っていても、グローバル変数と変わりありませんね。
- redfox63
- ベストアンサー率71% (1325/1856)
グローバル変数の実体をヘッダーに定義しているのが原因なのでは ・・・ // Test.h namespace TEST_SAPCE { extern int d; extern short h; } として 外部定義ですとしておいて // Test.cpp namespace TEST_SAPCE { int d; short h; } といった具合に 実体をCPPファイルで行いましょう
お礼
ヘッダーに実体を書かくと重複してしまうようですね。
- Tacosan
- ベストアンサー率23% (3656/15482)
何を言っているのかわかりません. 具体的かつ簡単な例は出せませんか?
お礼
TEST.Hを使うヘッダーが幾つもある所為で、ERRORがでるようです。
補足
簡単な例は、 //============TEST.H==========// #pragma once namespace TEST_SAPCE { int d; short h; } //============DOODLE.H(TEST.Hを使うヘッダー)==========// #include "TEST.h" ~ 以下略 ~ //========MAIN.CPP=======// #inlcude "DOODLE.h" int main() { int c; }
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
おそらくは、namespace が問題というより、単に、インクルードファイルの2十四見込みが発生しているだけという気がしますが。 この場合、インクルードガードと呼ばれる手法があります。 マイクロソフトの処理系だと、ヘッダファイルの先頭に #pragma once と書くだけです。 汎用的な方法としては、ヘッダファイルの先頭に #if !defined(ABCDEF) #define ABCDEF と書き、ヘッダファイルの最後に #endif を置く方法があります。 上の例で書いた、ABCDEF は、それぞれのヘッダファイルで一意になる名前(たとえば、プロジェクト名+ヘッダファイル名など)です。 このファイルが読み込まれた場合、最初は、(上の例では) ABCDEF が定義されていないので、ABCDEF を定義した上で、ヘッダファイル全体が有効になります。 2度目以降に読み込まれたとき、すでに ABCDEF が定義されているので、#if !defined() という条件に一致しなくなり、これ以降 #endif までがなかったことになります。
お礼
ちなみにエラーはLNK2005です 下記はERROR出力です error LNK2005: "int TEST::d" (?d@TEST@@3HA) は既に XXXXX.obj で定義されています。 ヘッダーにはnamespaceで実体を定義するのはまずいみたいです。
補足
#pragma once をしているのに、重複しているといわれます。
お礼
なるほど、#defineを使ってソースファイルで定義することにより一度しか読み込まなくなるんですね。 それで重複定義を防げると。 大変参考になりました。