プロが教える店舗&オフィスのセキュリティ対策術

 こんにちは。
C++を勉強しています。
今回は、namespace宣言して使いたいのですが、ヘッダー内でnamespace宣言をすると重複してしまいます。namespaceで定義したものを他のファイルでも使いたい場合はどうすればいいでしょうか?
よろしくお願いします。

A 回答 (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;
}
    • good
    • 0
この回答へのお礼

 なるほど、#defineを使ってソースファイルで定義することにより一度しか読み込まなくなるんですね。 それで重複定義を防げると。
 大変参考になりました。

お礼日時:2011/01/29 10:44

Visual C++限定で良いのであれば、



namespace Test
{
__declspec(selectany) int g_variableName;
}

のようにしてしまえばインスタンス生成が1回だけ行なわれるようになるので、ヘッダに宣言(Declaration)と定義(Definition)をまとめて記述できちゃいますが、それ以外のコンパイラの場合は他の回答者の方々が例示してらっしゃるように、ヘッダ側に宣言を記述(公開)して、ソースファイル側に実体を定義(実装)するようにします。

ただC++ではグローバル変数なんぞ使わないほうが無難です。
最悪でもstaticメンバーを使ってシングルトン実装にするのが定石かと。

ちなみに変数でなくconstを付けた定数であれば、C++の場合デフォルトで内部リンケージなので、ヘッダでも宣言と定義を記述できるようになっています。これにより、C言語でよく使われていたマクロ定数がほとんどの場面で不要になります。

namespace Test
{
const double PI = 3.141592653589793238;
}
    • good
    • 0
この回答へのお礼

 constを付けた場合だと重複定義にならないんですね。
参考書でconstを勧める意味が分かりました。

お礼日時:2011/01/29 10:49

既に答は出てるから蛇足だけど, 名前空間内だからといって特別なことはないんだよね.


ヘッダで
int x;
とかやったらダメというのはいいよね? namespace で囲まれてるけど, 基本的にはこれと同じこと.
無名名前空間だとヘッダで定義しても二重定義にならないから話は違うけど, それで何を期待するのかはやっぱりわからん.
    • good
    • 0
この回答へのお礼

 namespaceで括っていても、グローバル変数と変わりありませんね。

お礼日時:2011/01/29 10:47

グローバル変数の実体をヘッダーに定義しているのが原因なのでは ・・・



// Test.h

namespace TEST_SAPCE
{
  extern int d;
  extern short h;
}
として 外部定義ですとしておいて


// Test.cpp
namespace TEST_SAPCE
{
  int d;
  short h;
}
といった具合に 実体をCPPファイルで行いましょう
    • good
    • 0
この回答へのお礼

 ヘッダーに実体を書かくと重複してしまうようですね。

お礼日時:2011/01/29 10:45

何を言っているのかわかりません.


具体的かつ簡単な例は出せませんか?

この回答への補足

簡単な例は、
//============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;
}

補足日時:2011/01/18 13:43
    • good
    • 0
この回答へのお礼

TEST.Hを使うヘッダーが幾つもある所為で、ERRORがでるようです。

お礼日時:2011/01/18 13:45

おそらくは、namespace が問題というより、単に、インクルードファイルの2十四見込みが発生しているだけという気がしますが。



この場合、インクルードガードと呼ばれる手法があります。
マイクロソフトの処理系だと、ヘッダファイルの先頭に

#pragma once

と書くだけです。

汎用的な方法としては、ヘッダファイルの先頭に

#if !defined(ABCDEF)
#define ABCDEF

と書き、ヘッダファイルの最後に

#endif

を置く方法があります。
上の例で書いた、ABCDEF は、それぞれのヘッダファイルで一意になる名前(たとえば、プロジェクト名+ヘッダファイル名など)です。

このファイルが読み込まれた場合、最初は、(上の例では) ABCDEF が定義されていないので、ABCDEF を定義した上で、ヘッダファイル全体が有効になります。
2度目以降に読み込まれたとき、すでに ABCDEF が定義されているので、#if !defined() という条件に一致しなくなり、これ以降 #endif までがなかったことになります。

この回答への補足

#pragma once をしているのに、重複しているといわれます。

補足日時:2011/01/18 13:37
    • good
    • 0
この回答へのお礼

ちなみにエラーはLNK2005です

下記はERROR出力です
error LNK2005: "int TEST::d" (?d@TEST@@3HA) は既に XXXXX.obj で定義されています。

ヘッダーにはnamespaceで実体を定義するのはまずいみたいです。

お礼日時:2011/01/18 14:43

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!