今日は、ヘッダファイルの書き方について
の話になります。
今までは、短いサンプルということもあり、
一つのソースファイル(.cpp)の中に
クラスの定義を記述していました。
しかし、普通はクラスの定義はヘッダファイル(.h)に
記述し、メンバ関数の定義をソースファイル(.cpp)に記述します。
つまり、画像の例でいうと、Peach.h にこれを書いて、
class PeachBox {
public:
PeachBox();
~PeachBox();
int GetTotal();
private:
int m_total;
};
PeachBox::PeachBox():
m_total(0)
{
}
PeachBox::~PeachBox()
{
std::cout << "桃の化粧箱オブジェクトが終了します。" << std::endl;
}
int PeachBox::GetTotal()
{
return m_total;
}
int main(void)
{
PeachBox myPeachBox;
std::cout << "化粧箱の中の桃の数は" << myPeachBox.GetTotal() << "個です。" << std::endl;
return 0;
}
さて、このようにヘッダファイルとソースファイルを分割したことによって、
例えばFood.hといった他のヘッダファイルでPeach.hをインクルードする、
あるいは Peach.cpp から Food.h をインクルードするといった、
少し規模が大きいプログラムでも便利に使えるようになります。
しかし、色々なファイルで #include を使っていると、結果的には同じヘッダファイルを
2度インクルードしてしまうこともあります。
この場合は、クラスを2度定義することになり、コンパイルエラーになります(-_-;)
試しにPeach.h では Food.h をインクルードしてみます。
#include "Food.h"
class PeachBox {
public:
PeachBox();
~PeachBox();
int GetTotal();
:
そして、Peach.cppを、こんな感じに変更します。
#include <iostream>
#include "Food.h"
#include "Peach.h"
PeachBox::PeachBox():
m_total(0)
{
}
:
実際やってみると、Food.hを2回インクルードしているので、もちろんエラーです(^^;)
ちなみに、Peach.h Peach.cpp は同じディレクトリにあるので
これでコンパイルできています。
これでコンパイルできています。
# g++ -g -Wall -o Peach Peach.cpp
In file included from Peach.h:1:0,
from Peach.cpp:3:
Food.h:4:7: error: redefinition of ‘class Food’
Food.h:4:7: error: previous definition of ‘class Food’
#ifndef マクロ というプリプロセッサ命令があります(^^)
プリプロセッサとは、コンパイラに対してコンパイルする前に、
事前処理を行わせるためのプログラムのことです。
言葉だけでは、伝わらないので実際に使ってみます。
Food.h
ifndef __FOOD_H // もし、__FOOD_Hが未定義なら
#define __FOOD_H // 最初のインクルードで__FOOD_Hを定義します
// こうすることで、2回目以降は既に__FOOD_Hが
// 定義されているので、この内容は
// インクルードされなくなります(*^^)v
#include <iostream>
#include <string.h>
class Food
{
public:
static double sm_tax;
void SetPrice(int price);
int GetPrice(void);
private:
int m_price;
};
#endif // __FOOD_H ←通常、目印としてコメントを記述しておきます
Peach.h
#ifndef __PEACH_H
#define __PEACH_H
#include "Food.h"
class PeachBox {
public:
PeachBox();
~PeachBox();
int GetTotal();
private:
int m_total;
};
#endif // __PEACH_H
Peach.cpp
#include <iostream>
#include "Food.h"
#include "Peach.h"
PeachBox::PeachBox():
m_total(12)
{
}
PeachBox::~PeachBox()
{
std::cout << "桃の化粧箱オブジェクトが終了します。" << std::endl;
}
int PeachBox::GetTotal()
{
return m_total;
}
int main(void)
{
PeachBox myPeachBox;
std::cout << "化粧箱の中の桃の数は" << myPeachBox.GetTotal() << "個です。" << std::endl;
return 0;
}
# g++ -g -Wall -o Peach Peach.cpp
# ./Peach
化粧箱の中の桃の数は12個です。
桃の化粧箱オブジェクトが終了します。
2重インクルードしているにもかかわらず、エラーにならず実行できました。
ただ Food.cpp を作成してメンバ関数を定義していないし、
Peach.cpp 内で使ってもいないので、
Food.h をインクルードする必要のない、
例によって全くおもしろみもないプログラムです...(^^;)
ここでは、重複インクルード防止のための方法として、
#ifndef, #define, #endif という構文を見てきました。
プリプロセッサを使いこなして、品質の良いプログラムを造っていきたいものです。
今日の名言
子供には過去も未来もない、だから現在を楽しむ - 大人はとてもそうはいかない。
ジャン・ド・ラ・ブリュイエール
明日をはじめる前に今日をすっかり終える。今日と明日との間に眠りの壁を置く。
これをやり遂げるには、節制の心がけが必要だ。
ラルフ・ワルド・エマーソン
ある者は過去の記憶を蒸し返して、我と我が身を苛み続ける。
ある者はまだ見ぬ罪におびえて、我と我が身を傷つける。
どちらも愚かきわまることだ。 - 過去はもはや関係がなく、未来はまだ来ぬ・・・。
セネカ
時の真の価値を知れ。引っ掴め。押さえつけろ。そしてその瞬間瞬間を楽しめ。
怠けず、だらけず、ぐずぐずするな。今日できることを明日まで伸ばすな。
チェスターフィールド卿