第7章 ファイルを分けよう

 前回のプログラムは複数のファイルを利用していました。第1部第70章で話はしましたが、今まではあまりそういうことはしてこなかったので、ちょっと面食らった人もいたかと思います。

 しかし、これからはコードが多くなってくることもあり、ファイルを分けて話をしていくことが多くなると思います。なので、ここでクラスを作るときに便利なファイルの分け方について話してみようと思います。


 それでは、今回の要点です。


 では、いってみましょう。


 クラスも構造体もそうですが、

// Test1.cpp
class CTest
{
public:
    int a;
};

CTest a;
// Test2.cpp
class CTest
{
public:
    int a;
};

CTest b;

としても二重定義にはなりません。あまつさえ、

// Test1.cpp
class CTest
{
public:
    int a;
    int b;

    void Func();
};

void CTest::Func()
{
    b = 0;
}

CTest a;
// Test2.cpp
class CTest
{
public:
    int a;

    void Func();
};

CTest b;

int main()
{
    b.Func();
}

としても、何のエラーも出ません。Test2.cpp の方では CTest のメンバ変数として b は定義されていません。それなのに、この謎のメンバ変数が使えてしまうのです。(危険なので、実行はしません。)

 しかし、

// Test1.cpp
class CTest
{
public:
    int a;

    void Func();
};

void CTest::Func()
{
    a = 0;
}

CTest a;
// Test2.cpp
class CTest
{
public:
    int a;

    void Func();
};

void CTest::Func()
{
    a = 0;
}

CTest b;

int main()
{
    b.Func();
}

とすると、CTest::Func の二重定義エラーになります。

 このように、クラスの宣言は異なるファイルにあっても二重定義にはなりません。それどころか、そうしなければ2つ以上のファイルで使うことができません。ただし、同じファイルに2つ以上あるのはいけません。

 なので、ヘッダファイルにクラスの宣言を書いておき、それをインクルードするようにすると便利です。

 一方、その実装部はソースファイルに書きます。ヘッダファイルに書くと最後の例と同じことになり、二重定義になるからです。だだし、

// Test1.cpp
void CTest::Func()
{
    a = 0;
}
// Test2.cpp
class CTest
{
public:
    int a;

    void Func();
};

CTest b;

int main()
{
    b.Func();
}

はエラーになります。実装するときにはクラスの宣言が必要なのです。なので、実装を行っているファイルの方でもヘッダファイルをインクルードする必要があります


 まとめてみると、

// Test1.h
#ifndef __TEST1_H_INCLUDED__
#define __TEST1_H_INCLUDED__

class CTest
{
public:
    int a;

    void Func();
};

#endif
// Test1.cpp
#include "Test1.h"

void CTest::Func()
{
    a = 0;
}
// Test2.cpp
#include "Test1.h"

int main()
{
    CTest a;
    a.Func();
}

という感じになります。

 Test1.hCTest の宣言を行っていますね。そして、Test1.cppその実装をしています。で、Test1.cpp と Test2.cpp の両方で CTest の宣言が必要になるので、両ファイルとも Test1.h をインクルードしています。

 ワンパターンにこういう風にしていてもあまり問題はないとは思います。ですが、問題が出たときは頭の中でインクルードファイルを展開してみて下さい(第1部第27章参照)。

// Test1.cpp
// Test1.h
#ifndef __TEST1_H_INCLUDED__
#define __TEST1_H_INCLUDED__

class CTest
{
public:
    int a;

    void Func();
};

#endif

void CTest::Func()
{
    a = 0;
}
// Test2.cpp
// Test1.h
#ifndef __TEST1_H_INCLUDED__
#define __TEST1_H_INCLUDED__

class CTest
{
public:
    int a;

    void Func();
};

#endif

int main()
{
    CTest a;
    a.Func();
}

 こうすれば、問題があった場合、どこが悪かったのかが分かってくると思います。(上のプログラムには問題はありませんが。)


 では、今回の要点です。


 「さー、こうやって下さい」だけではいろいろ誤解する人が多いのでぐだぐだ言ってきましたが、要はこれだけのことをしていれば構いません。

 しかし、ちょっと例外があったりします。それはまた次回に話します。それでは。


第6章 デストラクタ | 第8章 インライン関数・再び

Last update was done on 2000.8.7

この講座の著作権はロベールが保有しています