C++ ファイル構成【ヘッダファイルとソースファイルの管理方法】

C++
この記事は約6分で読めます。

こんにちは、ナナです。

ソフトウェアシステムというものは、複数のファイルを組み合わせて大規模なシステムを構築していきます。

C++のプログラムは、拡張子「*.cpp」のソースファイルと拡張子「*.h」のヘッダファイルで構成されます。

課題となるのは、C++のシステムをどのようなファイル構成で作ればよいのかです。

C++のファイル構成の課題
  • ファイルをどのような単位で分けるべきなのか?
  • 「ヘッダファイル」と「ソースファイル」には何を記述すべきなのか?

これらの課題の対処法を身に付けておきましょう。

スポンサー

C++におけるファイル分割の単位

師匠!C言語でもC++でも、プログラムは「ソースファイル」と「ヘッダファイル」からできてますよね。

ということは、C++においてもファイル分割の考え方はC言語と一緒なんですか?

ナナ
ナナ

確かに「ソースファイル」と「ヘッダファイル」というファイル種類は同じなんだけど、ファイル構成の組み立て方はC言語とC++では少し異なるんです。

C言語のファイル分割は『C言語 ファイル分割の考え方【何を基準に分けるのかを解説】』で解説した通り、「モジュール」という単位で行うのが一般的です。

それでは、C++におけるファイル分割の仕方を学びましょう。

C++におけるファイル分割はクラス定義単位

C++はオブジェクト指向言語であり「クラス」こそが中心の言語です。そのため、「クラス」の定義単位でファイルを分割します。

クラスに対して1つのソースとヘッダファイル

各ファイル名については「クラス名.cpp」「クラス名.h」にしておくとよいでしょう。

ナナ
ナナ

つまり、仮にクラスを10個定義したら10セットの「cpp」「h」ファイルを作るということになります。

クラスで構成されたシステム全体像とファイルの管理方法

クラス単位でファイルを分割したとすると、システム全体はどのような姿になるのでしょうか。

とあるクラスオブジェクト「A」が、別のクラスオブジェクト「B」「C」に指示を出すといった構成もオブジェクト指向では当たり前にあります。

クラスの連携

オブジェクト指向言語では、クラスオブジェクト同士が連携を取りながらミッションを遂行していきます。

実際のプログラムでは、システム全体を機能単位に分離してフォルダを分け、対象機能に関連したクラスのファイルをそのフォルダ配下に置くというのがよく行われる方法です。

システムのフォルダとファイルの管理方法
ナナ
ナナ

C++のシステムは大きなものになることが多いため、フォルダやファイルをしっかりと整理整頓して管理しておかないと後で後悔します。

スポンサー

C++のソースファイルとヘッダファイルに記述するもの

C言語では「ヘッダファイル」には、マクロ定義・型定義・プロトタイプ宣言の3つを書くのが基本でしたよね。

C++も同じなんでしょうか?

ナナ
ナナ

「ヘッダファイル」は対象の機能を使いたい時にインクルードするためのファイルですね。その考え方はC++においても変わっていません。

ただし、C++では「クラス」が基本となるため、クラスに関する情報をどのようにファイルにまとめるかを学びましょう!

「ヘッダファイル」に書くべきものがわかれば、おのずと「ソースファイル」に書くものがわかります。

ヘッダファイルの役割

C言語やC++において「ヘッダファイル」とは、別の機能を使うための情報を取り込むために利用されます。

ヘッダファイルの役割

C++では、とある「クラス」を利用するためには、そのクラスが提供するヘッダファイルを取り込む必要があることになります。

ナナ
ナナ

ヘッダファイルの基礎は『C言語 ヘッダファイルの書き方【サンプルフォーマットを公開】』を見て学びましょう。

C++の「ヘッダファイル」と「ソースファイル」に書くもの

次のプログラムを例に各ファイルへ振り分けてみましょう。

class POS
{
private:
    int x;
    int y;

public:
    POS();
    int setPos(int tmpx, int tmpy);
};

//  コンストラクタ
POS::POS()
{
    x = 0;
    y = 0;
}

//  メンバ設定するためのメンバ関数
int POS::setPos(int tmpx, int tmpy)
{
    x = tmpx;
    y = tmpy;

    return 0;
}

それでは、「ソースファイル」と「ヘッダファイル」に分離してみます。

#ifndef POS_H
#define POS_H

class POS
{
private:
    int x;
    int y;

public:
    POS();
    int setPos(int tmpx, int tmpy);
};

#endif
#include "POS.h"

//  コンストラクタ
POS::POS()
{
    x = 0;
    y = 0;
}

//  メンバ設定するためのメンバ関数
int POS::setPos(int tmpx, int tmpy)
{
    x = tmpx;
    y = tmpy;

    return 0;
}

このように、クラスの型定義はヘッダファイルに記述し、メンバ関数の実体定義はソースファイルに書きます。

POSクラスの利用イメージとしては、次のようになります。

POSクラスの利用シーン
スポンサー

Q&A:ファイル構成に関するよくある質問

Q:クラスの型定義の中でメンバ関数の定義がされたものを見ました!

師匠!わたくし、このサイト以外でもC++を巻物で勉強しております。その中でクラス定義で変わったものを見つけました。

なんと、クラス定義の中でメンバ関数の定義がされていたのです。メンバ関数の定義は「ソースファイル」なんでしょ?おかしいですよね?

ナナ
ナナ

えらいね~、勉強熱心な姿は感心するよ。書籍や他のサイトも色々見ながらC++を学ぶといいよ。

この記事ではまだ紹介しませんが、その巻物が示しているようにクラス定義の中でメンバ関数の定義を含ませる書き方があります。

実はヘッダファイルに記述するクラスの型定義の中で、メンバ関数の定義を行うこともできます。

#ifndef POS_H
#define POS_H

class POS
{
private:
    int x;
    int y;

public:
    POS();
    int setPos(int tmpx, int tmpy)
    {
        x = tmpx;
        y = tmpy;

        return 0;
    }
};

#endif

これは「インライン関数」と呼ばれるC++の新しい機能が影響しています。インライン関数に関しては別の記事で紹介しましょう。

ナナ
ナナ

現時点では、メンバ関数の定義は「ソースファイル」に書くのが基本として覚えてください。

スポンサー
C++C++入門
スポンサー
モノづくりC言語塾