C++初心者です.
下記のコード例のような場合……
関数の実装を書いている Func.cpp
では,関数の宣言が書かれている Func.h
を include する必要は無いです.
無いのですが……
自分は 何故か Func.cpp
に #include "Func.h"
を書いてしまいます.
でも,その理由が自分でもよくわかりません.
Func.cpp
なるファイルを用意した時点で半ば機械的に書いてるだけ?(単なる習慣?)- 「対応しているヘッダがこれだよ」っていうのを明記したいとかそういう何か?
あるいは,IDEでincludeの記述箇所からヘッダに飛べるみたいな利便性? - オーバーロード不可能な形でシグネチャを書き損じた場合とかにコンパイルエラーが欲しい?(限定的だなぁ)
- ???
考え出したら何もかもわからなくなってきました.
皆さん,このような場合,
#include "Func.h"
を書きますか? 書きませんか?- その理由って何でしょうか?
(まぁ,書かない側の理由は「要らないから」になるのでしょうけど)
C++
1//[Func.h] 2#pragma once 3 4class X; 5 6int Func1( int, double ); 7int Func2( const X& );
C++
1//[Func.cpp] 2#include "Func.h" //←※コレは不必要なinclude※ 3#include "X.h" //(これはclass X の定義が書かれているやつ) 4 5int Func1( int, double ){ /*...(略)*/ } 6int Func2( const class X& ){ /*...(Xの定義が必要な記述.略)*/ }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答16件
#1
総合スコア1528
投稿2025/07/29 12:59
あとで別の*.cpp
からFunc1
、Func2
を呼び出せるように...って、mainはどこにある前提?
そもそも、fanaさんはC++初心者ではないし、この引っかけ問題は難しい...
#2
総合スコア6155
投稿2025/07/29 13:29
私は、小さなプログラム&使い捨てる心づもり&自分しか読まないコードだとヘッダファイルは用意しません。そうでなければとりあえずお行儀良くヘッダファイルを準備します。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#3
あとで別の*.cppからFunc1、Func2を呼び出せるように...って、mainはどこにある前提?
おっしゃる通り, Func1()
や Func2()
は別の個所から使われる想定の話です.
引っかけ(?) とかではなく,ごくごくふつーのやつです.
Func1()
, Func2()
の実装者としては 「他所で使うのに宣言が欲しいだろうから → それを書いたヘッダを用意したぜ!」っていう.
main()
関数から使うとしたら以下のような.
C++
1//[別の翻訳単位] 2#include "Func.h" //関数の宣言が必要なので,用意されてるヘッダをありがたく使わせてもらうよ 3 4int main() 5{ 6 /* Func1() とか Func2() とかを使うよ */ 7}
要は,こんな感じで,この Func.h
ってのは「他の場所で」include するための物として用意しているものなわけで,少なくともこの例ではコレを Func.cpp
という翻訳単位が include する必要がない.
……んだけど,なぜか(体が勝手に?) include 書いちゃうんだよなぁ,なんでかなぁ……っていうだけの話です.
( 「 .cpp と対になる(?)感じで書いたヘッダ内に .cpp の実装が必要とする記述が無い」っていう状況というのがレアケースだから,そういうの考えずに脳死的に include しちゃってるのだろうか?)
※コード例が簡素なサンプルすぎるせいで書き捨てコードの話に見えてしまうかもしれませんが,ふつーに「(仕事でも趣味でもいいですが)実用するコード」での話だと思ってください.
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#5
総合スコア1528
投稿2025/07/30 14:46
以下の3環境で確認しましたが、Func.cpp
から#include "Func.h"
は不要なのですね。
あれ? 今日から私もC++初心者?
OS | コンパイラー |
---|---|
Windows 11 | Visual Studio 2022 |
FreeBSD 14.3 | g++ 16.0.0 |
FreeBSD 14.3 | clang++ 21.0.0 |
いずれも、標準C++23で確認。
X.h
#pragma once #include <iostream> class X { public: X(){}; void test() const { std::cout << "class X" << std::endl; }; };
Func.h
#pragma once class X; int Func1(int, double); int Func2(const X&);
Func.cpp
#include <iostream> #include "X.h" int Func1(int x, double y) { std::cout << "Func1" << std::endl; return 0; } int Func2(const X &x) { x.test(); return 0; }
test.cpp
#include "Func.h" #include "X.h" int main() { Func1(1, 1.0); X x; Func2(x); return 0; }
出力
Func1 class X
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#7
#4
将来誰かが Func.cpp
に手を入れた時に「何かわからんけど突然コンパイル通らなくなった」みたいな余計な混乱が生じるかもしれないことを防止,みたいな意味合いでしょうか.
なるほど,参考になります.
#5
その反応……どうやらあなたも「なぜだか不明だけど include 書いてた派」ですね!?
さぁ悩みましょう.
「それでも俺は…… Func.cpp
に #include "Func.h"
って書くんだ!」という道を貫くのか否か.
#6
関数オーバーロードが無い C であれば効く範囲もそれなりに広いでしょうけど,C++ だととても狭いですよね(戻り値の型が違うパターンだけかな).
それでもコンパイルエラーが出せるパターンがあるなら価値があるという感じですかね.
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#9
総合スコア47
投稿2025/08/05 09:57
一つのヘッダ内に互いに関連し合う複数のクラスがある場合、ヘッダをインクルードすることで、実装ファイルで手書きで前方宣言を書かずに済む場合があるかもしれませんね。
けれど、クラス相互の循環参照をなくすいつものテクニックを使えば、ヘッダを分けて、「ヘッダをインクルードせず」前方宣言も最小限にできると思うので、ちょっと微妙でしょうか?
間違っていたらすみません。ご参考までに。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#10
一つのヘッダ内に互いに関連し合う複数のクラスがある場合、ヘッダをインクルードすることで、実装ファイルで手書きで前方宣言を書かずに済む場合があるかもしれませんね。
実装ファイル(.cpp)で何らかのクラス群の宣言を必要とする(:定義は不要)という状態において,
その .cpp にそれらクラス群の宣言を書くのが 面倒/だるい/etc... というような話でしょうか.
(で,ヘッダにそれらの宣言があるならば,それを include しちゃうのが楽,っていう)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#11
総合スコア47
投稿2025/08/05 14:20
返信ありがとうございます。
自分の考えを整理したところ、以下のようなコードにまとまりました。
c++
1// header.h 2 3#ifndef HEADER_H 4#define HEADER_H 5 6// sleepyの内部実装がboyに依存しているとする。(両方ともpublicだから、ポリシーによってはありうる。) 7 8class A { 9public: 10 void sleepy(); 11 void boy(); 12}; 13 14#endif
c++
1// impl.cpp 2 3#include <iostream> 4 5// ヘッダをインクルードする場合、それだけでコンパイル可能。 6#if 0 7#include "header.h" 8#endif 9 10// ヘッダをインクルードしない場合、A::sleepy内でA::boyを参照するためには、ODR違反しないように、class Aの定義を一つのトークンも違えることなく再度書かなければならない。 11#if 0 12class A { 13public: 14 void sleepy(); 15 void boy(); 16}; 17#endif 18 19void A::sleepy() 20{ 21 boy(); 22} 23 24void A::boy() 25{ 26 std::cout << "do everything myself (without depending anything)" << std::endl; 27}
肝は、publicメンバ関数が、同じクラスのpublicメンバ関数に依存している、という部分です。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#12
肝は、publicメンバ関数が、同じクラスのpublicメンバ関数に依存している、という部分です。
sleepy()
が boy()
を必要とするか否かという話とは無関係に,まず
C++
1//impl.cpp 2void A::sleepy(){ /*...*/ }
っていうだけではコンパイル通らないんじゃないですかね.
この状況でヘッダをincludeすることは(本件のタイトルの文言とはちょうど真逆の)「必要なinclude」だと思います.
そこであえて「でも既存のヘッダファイルの存在を無視しつつ,そのヘッダファイル内の定義を手動で imp.cpp にコピーするのもいいよね!」という手段に出るというのは,さすがに普通ではないと思います.(そもそも,そんなことを毎度頑張ってやらなくても済むようにヘッダファイルとかいうのが用意されているのでは)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#13
総合スコア47
投稿2025/08/07 07:05
おっしゃるとおりです。
フリー関数のプロトタイプを実装ファイルで(ヘッダ経由で)繰り返すか?と、
クラス定義のプロトタイプを繰り返すか、という問題は、あまり関連がありませんし、後者の場合は、ヘッダのインクルードは否応なく必要ですね。
意見交換のトピックが、普段自分も考えたりすることでとても興味を惹かれたので、勢いで文脈から外れた投稿をしてしまいました。
元の議論についてですが、私はこういう場合は、あくまでコンパイル可能な最小のコードを書きたいと思うことが多いです。実装ファイルのコンパイル自体は
「 .cpp と対になる(?)感じで書いたヘッダ内に .cpp の実装が必要とする記述が無い」
という理想的な(ただしまれな)状況においては、ヘッダをインクルードしなくてもできるので、コンパイラ(リンカを除く)に少しでもトークン解析の負担を書けたくないな、と。(メモリが1Kだった時代じゃないよ、とセルフツッコミはしますが。)
けれど、主さんと同じく、実際にプログラムを書くときは、手の赴くままにヘッダをインクルードしてしまいますね。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#15
総合スコア479
投稿2025/08/12 13:40
C++はよく知りませんが、
Cレベルでは、Func.cpp と Func.hの間に
齟齬がないかどうかの確認のため。
C++でも、リンク時の関数名見直すことになるよりは分かりやすいと思います。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。