#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のトップページをご覧ください。