ホーム < ゲームつくろー! < IKD備忘録

Raspberry Pi
ヘッダーと.cppを作ってコンパイル


 Raspberry Piで(というかlinuxで)C++が最低限にできるようになりました。ちっこいRaspberry Piでプログラミングが出来たわけですから、楽しいやら嬉しいやら。

 でも、前回はmain.cppでprintf関数を呼び出しただけでして、それはC++じゃなくてC言語。やりたいのはC++なので、今回は「ヘッダーでクラスを宣言し、.cppでそれを実装。main.cppでクラスを使って何かする。」という最低限のC++をやってみます。



@ 扇風機クラス

 じゃぁ何を作ろうかと考えた訳です。暑い夏な東京の我が家。目に留まったのは扇風機。じゃ、プログラムの中で扇風機をON/OFFしてみようと。

 家の扇風機はON/OFFのスイッチがトグル(toggle)になっています。ボタンを押す度に「ON⇔OFF」と切り替わるスイッチです。扇風機クラスにはこのスイッチの状態(bPower)をboolで保持しておいてもらいましょう。扇風機の状態はgetStateStringメソッドで文字列として取得します。スイッチはpushSwitchメソッドで切り替える事にします。この最低限の機能を持った扇風機クラスのヘッダー部はこんな感じになりそうです:

electricfan.h
class ElectricFan {

    bool bPower;

public:
    ElectricFan();

    const char* getStateString() const;

    void pushSwitch();
};

実装部はこうです:

electricfan.cpp
#include "electricfan.h"

ElectricFan::ElectricFan() : bPower( false ) {
}

const char* getStateString() const {
    if ( bPower == true )
        return "Power On.";
    return "Power off";
}

void ElectricFan::pushSwitch() {
    bPower = !bPower;
}

で、メイン関数では扇風機を世界に置いて(作って)、スイッチを入れて、その状態を出力します:

main.cpp
#include <stdio.h>
#include "electricfan.h"

int main() {

    ElectricFan fan;

    fan.pushSwitch();   // Switch on

    printf( "Electric Fan State: %s", fan.getStateString() );

    return 0;
}

ほい、コードイメージはこんなもんです。これをRaspberry Pi上で実際打ち込んでいきます。



A .hと.cppファイルをvimで作成

 新規のプロジェクトなので、「~/prj/sandbox/electricfan」という新しいディレクトリをmkdirで作っときましょう。electricfanディレクトリに@で挙げた「electricfan.h」「electricfan.cpp」そして「main.cpp」ファイルを作ります。もちろんvimで(^-^)。新規に作るのは:eコマンドでした。

 コード量が増えたので、誤入力が出ます。vimで削除するのはdeleteキーなのかなと思ったのですが、どうもあんまりうまくいかない。どうやらノーマルモードで「x」を押すとカーソル上の一文字が削除される模様。

 使いながら「?」と思った事の一つが「右端に追加で書きたい時」。例えばノーマルモード時で、

とカーソルがElectricFan()の右側に位置している状態。この後に「;」を入れたい訳ですが、ここで挿入モード(i)にすると、

このように括弧の中に「;」が挿入されてしまいNG。カーソルをさらに右にしたくても、文字の終端なのでこれ以上右に行かない。文字の右端にさらに文字を挿入するには…(調査中)、おぉ「a」だそうです。やってみよう:

おお〜、カーソルが右括弧のさらに右に進んでくれました。そして入力モードになっているので、そのまま「;」を打てます。覚えた(^-^)。

 electricfan.hを打ち込み終わった後、:wで保存します。で、次にelecticfan.cppを作るためにノーマルモードで「:e electricfan.cpp」。vimの画面が更新されて、electricfan.cppを打つ環境になりました。.同様に打ち込み終わった後にmain.cppも作ってしまいます。最終的にelectricfanフォルダ下には3つのファイルができました:

文字の次に挿入「a」と一文字削除「x」。これを覚えて随分入力が楽になりました。少しずつ習得です(^-^)。

 さて、ではこれらの.cppをコンパイルします。



B 複数の.cppを分割コンパイル

 前回はmain.cppしかなかったので、g++に、

g++ main.cpp

としてコンパイルをお願いしたのでした。今回はelectricfan.cppもあります。複数の.cppファイルのコンパイルをお願いするには…(調査中)、なるほど、いわゆる「分割コンパイル」をするようです。つまり、「各.cppを個別にコンパイル」するという事。

 分割コンパイルをする場合、g++のコンパイラオプションの「-c」を付けます。これは「後に続く.cppだけをコンパイルしてね」というフラグです。ただ、分割でコンパイルするわけですから、当然実行ファイルは出力されません(作れませんので)。その代わり「オブジェクトファイル」というファイルが出力されます。オブジェクトファイル(Wikipediaはこちら)とは.cppをコンパイルした結果出来る中間コードで、マシン語で書かれたコードや各種情報が格納されています。Visual StudioでもコンパイルするとDebugフォルダ等の中に「.obj」というファイルができますよね。あれが、オブジェクトファイルです。

 分割コンパイルでオブジェクトファイルを出力するには、次のようにコマンドを打ち込みます:

g++ -c main.cpp -o main.o

-cオプションで「分割コンパイルしてね」、続く-oオプションが「オブジェクトファイルを出力してね」です。main.cppとelectricfan.cppそれぞれについて、オブジェクトファイルを作ってみます:

お〜〜、ちゃんと各.cppのオブジェクトファイルが出来てます。

 これらオブジェクトファイルはコードの断片のようなものです。実行ファイルを作るにはこれらのオブジェクトファイルを繋ぎ合わせる必要があります。いわゆる「リンク」です。オブジェクトファイルをリンクするには、g++に各オブジェクトファイルを連ねるだけです:

g++ main.o electricfan.o

すると…:

a.out実行ファイルができました〜〜。で、実行してみると、

きた〜「Electric Fan State: Power ON」!想定した通りの出力をしてくれました。やったぜ!これで夏の暑さも耐えきれる(笑)

 という事で、分割コンパイルとリンクを学べましたが、ファイルが増えて来るとこの作業があっという間に破綻するのが簡単に想像できます。だって、ちょっとした規模のゲームを作っても.cppの数は数十から数百になります。コードを変更する度に上のコマンドラインを打ち直していたら夜が明けてしまいますし、そもそもヒューマンエラーの大温床です。これを回避するには「コンパイルとリンクの自動処理」が絶対に必要になります。

 それをしてくれるのが、いわゆる「メイク(make)」です。次の章で見て行こう(=調査しよう(^-^;)。