はじめて投稿させていただきます。
同じヘッダファイルを複数のcppファイルから読み込む場合、
二重の宣言を防ぐために
#pragma once
(VCの場合)
や
#ifndef _HEADER_H_
#define _HEADER_H_
/*
コード
*/
#endif
とすればよいということはわかったのですが、
うまくいきません。
たとえば
hoge.h
foo.cpp
bar.cpp
とあった場合
//- hoge.h -----------------------------------------------------------------
#ifndef _HOGE_H_
#define _HOGE_H_
int a(){
return 0;
}
#endif
//- foo.cpp -----------------------------------------------------------------
#include hoge.h
void main(void){
}
//- bar.cpp -----------------------------------------------------------------
#include hoge.h
---------------------------------------------------------------------------
ビルドすると
VC6++でも
VC++ .NET2003 でも
「bar.obj : error LNK2005: _a はすでに foo.obj で定義されています」
と出てしまいます。
クラスとメンバ関数は inline展開にしてやると通ったのですが・・・
なにが問題なのでしょうか。
ひとつのソースファイルで
#include hoge.h
#include hoge.h
と二度定義するのは大丈夫だったのですが・・・
環境は
WinowsXP
VisualStudio 6.0
です。
よろしくお願いします。
リンカーの出した警告(またはエラー報告)だということはお分わりですか?
二(多)重インクルードが問題になるのは普通はコンパイル時のことだと思います
ヘッダーに函数(かんすう、関数)の定義(プロトタイプ宣言でなく)をかいているから
なんじゃないんでしょうか
#include hoge.h とヘッダーを読み込むように指定したソースそれぞれに int a()
というスタチックでない函数が定義しているものだから、コンパイラーは言われた通り
にその函数をコンパイルしますが、リンカーが複数のオブジェクトファイルに同じ名前で
同じ戻り値の型で、同じ引数の並びの函数があることに気付いて親切に教えてくれている
のでしょう
返答ありがとうございます。
リンカが出している警告だというのは、
objに対しての警告なのでわかります。
ヘッダファイルには
グローバル変数やグローバル関数。
インライン指定(?)以外でのクラスのメンバ関数
というのはできないということなのでしょうか?
どこかでできる。というような記述を見かけたのですが。
以下のような形で用意するしかないということでしょうか?
//- hoge.h -----------------------------------------------------------------
#ifndef _HOGE_H_
#define _HOGE_H_
int a();
extern b;
#endif
//- hoge.cpp -----------------------------------------------------------------
#include hoge.h
int b;
int a();{
return 0;
}
//- foo.cpp -----------------------------------------------------------------
#include hoge.h
void main(void){
b+=2;
}
---------------------------------------------------------------------------
宣言と定義との違いはお分かりですか?
>//- hoge.h -----------------------------------------------------------------
>#ifndef _HOGE_H_
>#define _HOGE_H_
>int a();
>extern b;
>#endif
今回の例では宣言しかありませんが下に示す前回の例では
>>//- hoge.h -----------------------------------------------------------------
>>#ifndef _HOGE_H_
>>#define _HOGE_H_
>>int a(){
>> return 0;
>>}
>>#endif
のように函数(かんすう、関数)の定義が書いてありますね
先ほどの説明のどこが分かり難(にく)かったのでしょうか?
>ヘッダファイルには
>グローバル変数やグローバル関数。
>インライン指定(?)以外でのクラスのメンバ関数
>というのはできないということなのでしょうか?
御免なさい、質問の意味がわかりません。
できないとは何が出来ないということなんでしょうか?
すいません。最後の質問は言葉が足りませんでした。
ヘッダファイル内で、
関数を宣言し、
その関数を複数のソースファイルから
利用することは可能ですか?
>ヘッダファイル内で、
>関数を宣言し、
>その関数を複数のソースファイルから
>利用することは可能ですか?
宣言というのは定義とは違い内容(値や振る舞い)について記述しません
型に付いてコンパイラーや読み手に知らせるためのものですから
そういう使い方をするのがヘッダーファイルの役割だと思います
ですから、可能というよりは、そのような使い方をするものでしょう
なるほど。
たしかにヘッダファイルは
コンパイルしてオブジェクトファイルを作るものではありませんし、
ヘッダファイルには定義を。
宣言はソースファイルに記述すべき。
ということなのですね。
勉強になりました。
お付き合い戴き、ありがとうございました。
>ヘッダファイルには定義を。
>宣言はソースファイルに記述すべき。
どうしてそうなるんでしょうか?
私の書き方のどこがいけなかったのでしょうか?
逆なんですけど....
それに、すべきとも書いてないんですけど....
>ヘッダファイルには定義を
#defineとかtypedefとかあるので
まぁ間違いではないでしょうな
本人がどういう意味で使っているのかは知りませんが
>ヘッダファイル内で、
>関数を宣言し、
>その関数を複数のソースファイルから
>利用することは可能ですか?
大方これも
「ヘッダーファイルで関数を定義して利用できるか」
の間違いなのでは?
宣言して利用することが可能なのはできているようだし
本当にそうすることに意味があるのかを再考すべきだとは思いますが、
この疑問に対しての表面的な回答としては、無名名前空間を使えばいいのではないかと。
=== hoge.h ===
#ifndef _HOGE_H_
#define _HOGE_H_
namespace { // 無名名前空間ここから
int a(){
return 0;
}
} // 無名名前空間ここまで
#endif