#pragma twice

KAB-studio > プログラミング > #pragma twice > 304 Version 15.04 ヘッダーファイルは必要?

#pragma twice 304 Version 15.04 ヘッダーファイルは必要?

前のページへ 表紙・目次へ 次のページへ

 Version 15.04
ヘッダーファイルは必要?

前回は、ヘッダーファイルはただの置き換え、ってことを説明しました
まさかソースファイル代わりになるとは……ん? でもそしたら、
ソースファイルとヘッダーファイルの違いって? ただの置き換えなら、
どっちかだけでもいいんじゃない?
確かにそうだけど、実際はふたつに分けた方が楽だから分けてあるんで

分けた方が楽?
まずルールとして、基本的にヘッダーファイルはコンパイルできませ

え、そうなの?
 VC++ が〈コンパイルするのは、拡張子が .c か .cpp のみ〉って決めて
るから。あ、あと .cxx も大丈夫かな
ってことは、 .h のヘッダーファイルは
コンパイルされません。だから、プログラムを作るためには Main.cpp と
かのソースファイルが必須。このファイルがないとコンパイルされないから

ソースファイルは必須、と……じゃあヘッダーファイルがどうかってこと
よね
そう。理論上は、ヘッダーファイルは必要ないんだけど、あった方が便利
です。まず、 Sub.cpp と Sub.h に話を絞って考えてみます。 Main.cpp も
含めて、3ファイルがこういう状態の場合

// Main.cpp
#include <Windows.h>

#include "Sub.h"

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    Test();
    return 0;
}


// Sub.cpp
#include <Windows.h>

void Test()
{
    MessageBox( NULL, "サブ", "Sub()", MB_OK );
}


// Sub.h

void Test();

うん、普通に動くね
次に、 Sub.cpp に Test2() という関数を追加して、 Test() から呼び出
す場合を考えます

// Sub.cpp
#include <Windows.h>

void Test()
{
    Test2();
}

void Test2()
{
    MessageBox( NULL, "テスト2", "Test2()", MB_OK );
}

うん、 Test() から Test2() を呼んでるね
でも、これだとコンパイルエラーになります

Sub.cpp(6) : error C2065: 
    'Test2' : 定義されていない識別子です。
Sub.cpp(10) : error C2373: 
    'Test2' : 再定義されています。異なる型修飾子です。

ホントだ。……あ、もしかして Test2() が Test() の後にあるから?
そう! 関数を使うためには、その関数の定義か宣言が呼び出す前にない
とだめなんです
定義か宣言、どっちかでいいんだ。ってことは

// Sub.cpp
#include <Windows.h>

void Test2()
{
    MessageBox( NULL, "テスト2", "Test2()", MB_OK );
}

void Test()
{
    Test2();
}

うん、これならコンパイル通った。あと、宣言でもいいんだから……

// Sub.cpp
#include <Windows.h>

void Test2();

void Test()
{
    Test2();
}

void Test2()
{
    MessageBox( NULL, "テスト2", "Test2()", MB_OK );
}

うん、これもOK!!
あともう1パターン!
え……あ、そっか、ヘッダーファイル!

// Sub.cpp
#include <Windows.h>

#include "Sub.h"

void Test()
{
    Test2();
}

void Test2()
{
    MessageBox( NULL, "テスト2", "Test2()", MB_OK );
}


// Sub.h

void Test();
void Test2();

これでもOKだね
さて、ヘッダーファイルを使うと便利、つまり一番最後の方法が一番便利
ってことを説明します。まず、最初の方法、 Test2() を Test() の前に
持ってくる方法
これは面倒そう……呼び出す関数を必ず上に持っていかなきゃいけないん
だから
そういうこと。特に関数同士が複雑に呼び合っている場合には、パズルに
なっちゃいます。なので、そういう〈順番〉を気にしなくていい、宣言を先
に書いておく方法が必須になります
で、それをヘッダーファイルにまとめる理由ね。うーん……
もし Sub.cpp だけなら、2番目の方法でも問題ないと思うよ
 Sub.cpp だけなら……ってことは、他のソースファイルから呼び出す場
合のため、ってこと?
そういうこと。コンパイルってソースファイル単位ですることを思い出し

うん、一番手前のソースファイルだけコンパイルしてた
ってことは、ヘッダーファイルのインクルードをして、関数の宣言を憶え
ておく、っていうのもソースファイル単位ってこと
???
たとえば、 Sub.cpp をコンパイルしたとします。そうすると、 Test() 
と Test2() の宣言が出てきてるよね
うん
次に、 Main.cpp がこうなってた場合

// Main.cpp
#include <Windows.h>

// #include "Sub.h"

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    Test();
    return 0;
}

あ、インクルードがコメントアウトされてる……
この状態だとコンパイルエラーになります。 Sub.cpp をコンパイルして
続けて Main.cpp をコンパイルしても、 Sub.cpp をコンパイルしたときの
情報、つまり Test() と Test2() の宣言がある、っていう情報はなくなっ
てるから
 Test() なんて関数は存在しない、と
だから、〈 Sub.cpp の関数を呼び出すソースファイルは、全て Sub.cpp 
の関数の宣言を持たなきゃいけない〉ことになります
宣言を持つ……

// Main.cpp
#include <Windows.h>

void Test();
void Test2();

int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    Test();
    return 0;
}

ってすればいいってことよね。でもめんどくさ……あ! そのための
ヘッダーファイル!
そういうこと。インクルードすればいいわけでしょ。ソースファイルにあ
る全関数の宣言をヘッダーファイルに書いておけば
そのヘッダーファイルをインクルードすれば使えちゃう!
そういうこと

/*
    Preview Next Story!
*/
ヘッダーファイルってそういう便利さがあったのね
と言っておいてなんだけど、実は面倒な部分もかなりあるんです
げ!
たとえばインクルードする順番とか
順番? そんな気にしなくてよさそうだけど
というわけで次回
< Version 15.05 インクルードの順番 >
につづく!
ほんっとうに悩まされるんだ、これが……
経験者は語る、ね……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。