オブジェクトの広場は株式会社オージス総研グループのエンジニアによる技術発表サイトです

プログラミング

Javaプログラマに贈るC++入門(第1回)

〜 Hello, C++ !! 〜
株式会社オージス総研
ビジネスプロセスソリューション部
金子 平祐
2004年2月27日

Java全盛の時代ではありますが、C++によって開発をしなければならない/した方がよい案件はまだまだ数多く存在します。その一方で、Javaからこの業界に入ってくる人がますます増えてきているのもまた事実です。本連載では、これまでJavaでオブジェクト指向プログラミングを実践されてきた方が、ある日突然C++を使うことになったときのための学習ポイントを、筆者の実経験をもとにお送りしていきます。

目次

  1. はじめに
  2. 開発環境の準備
  3. Hello C++!!
  4. プログラムの入り口
  5. メソッド と 関数
  6. まとめ & 次回予告

1. はじめに

「Do you love Java?」

こう聞かれたら、読者の皆様はどう答えますか?

筆者は「Yes, I love Java : )」と、満面の笑みで答えます。 なぜなら、 Java は、 手続き型でプログラミングをしていた筆者に、 「オブジェクト指向の何たるか」を手取り足取り優しく教えてくれました。 Java はマルチプラットフォーム性を重視していますから、 同一のプログラムを Windows マシンでも Linux マシン でも動かすことができます。 また、 GUI から ネットワーク、マルチスレッド関係までも網羅する豊富な API を備えているので、 ちょっとした処理ならば、これらの API を組み合わせるだけで簡単に実現できてしまいます。 それになんといっても、GC(ガーベッジ・コレクション)のおかげで、バグの温床であるメモリ管理をプログラマがおこなう必要がありません♪ もちろん、良い面があれば、悪い面もあるのが世の常。 Java の場合も御多分に漏れず、 主に「実行性能の低下」というデメリットが存在します。 それにもかかわらず、 ここ数年、Java はプログラミング言語界において No.1 の地位を固持し続けてきました。 書店には Java 関連の書籍・雑誌が山のように並んでいます。 新入社員や学生のプログラミング入門には Java が使われています。 Web アプリケーション 絡みの新規案件は Java による開発がほとんどを占めています。

それでは、この飛ぶ鳥を落とす勢いの Java 1 本だけで、 私達エンジニアはご飯を食べていくことができるのでしょうか? おそらく、この質問に対する答えは エンジニアの所属する業界によって異なるでしょう。 まず間違いなく、 Web アプリ開発をメインとする SE は、 現在 そして 今後数年間、 Java 中心の開発を続けていくことができるはずです。 しかし、デスクトップアプリケーション および 組み込み分野 においては、 まだまだ Java による開発のお仕事は少ないのが現状です。 理由は簡単で、これらの分野では、 「ハードウェアスペックが限定されている」状況下で、 「応答性を極力上げなければならない」という要求が存在するからです。

もちろん、最新スペックの PC ならば Java で書かれた デスクトップアプリケーションも快適に稼動します。 しかし、私達人間のために働いてくれている世の中の PC 君たち全てが十分なスペックを持っているわけではありません。 おそらく、CPU が 数百MHz、メモリも 128〜256MB 程度しか積んでいないマシンを 現役バリバリに使っている企業・オフィスも未だ多いのではないでしょうか。 残念ながら、 こういったマシンでは Java アプリは満足のいくレスポンスを返してくれず、 ユーザに多かれ少なかれストレスを与えてしまいます。 したがって、 顧客側に高スペックの PC を用意してもらえることが前提となっている場合においてのみ、Java での開発を企画・提案することが出来るのです。 また、デスクトップ分野以上に状況が厳しいのが組み込みの世界です。 組み込みの世界は、 「製品の品質を上げる」ことと同等、あるいはそれ以上に、 「1 台あたりの製造コストを極力下げる」ことが重視されてしまうため、 Java をサクサク動かせるハードウェアを用意することは非常に難しいのです。

※ もっとも、皆様ご周知の通り ここ数年、 「どこどこのメーカが、 製品に搭載されているソフトウェアの不具合による回収騒動により、 多額の損失を計上。」 といった話題が新聞紙面を度々賑わしています。 こういった手痛い目を何度か経験した結果、 メーカサイドにも「多少製造コストが上がっても、品質を向上させなければならない。」 という意識が芽生えてきています。 その潮流の一端として、 組み込み分野においても 従来の手続き型 から オブジェクト指向への パラダイムシフトが行われている最中です。

以上の考察を要約しますと、 現時点においては、 デスクトップ および 組み込みの分野 では Java を開発言語に選択することができるとは限らない、ということになります。 では、オブジェクト指向による開発をしたいが、 Java による開発ができない場合に 私達エンジニアが取るべき道とは何でしょうか?

そう、C++ を利用するのです。

オブジェクト指向によって、「保守性」、「再利用性」、「拡張性」etc. を向上させたいけれど、 その一方で、 リソース制限の厳しいハードウェアでも快適に稼動させなければならない。 こういった状況で選択する現実的な解の 1 つが「C++ による開発」なのです。

もちろん、C++ には 冒頭で触れた Java のメリットは存在しません。 C++ は仕様が膨大・複雑で、難解です。 C++ は移植性が考慮されていないので、 各 OS 毎に特化したプログラムを逐一作成しなければなりません。 C++ に標準で用意されている API は Java プログラマにとっては少なすぎます。 C++ ではプログラマがメモリ管理の責務を持たなければならず、 結果、バグだらけのソフトウェアが世の中に多数出回ってしまいます。 しかし、これらのマイナス要素と引き換えに、 優れた実行性能を手に入れることができるのです。

したがって、ここまで見てきましたように Java だけでなく C++ も使えたほうが、 エンジニアとして携われるお仕事の幅がグンと広がります。 筆者自身 ここ数年間 Java で OOP(オブジェクト指向プログラミング) してきたのですが、 昨年から組み込み系のお仕事に携わることになり、 C++ を使い始めることになりました。 最初はビクビクしながら歩を進めていたのですが、 既に Java でオブジェクト指向については理解していたせいか、 最大の難所のメモリ管理部分さえ克服してしまえば、 当初思い描いていたほど恐ろしい世界ではありませんでした。 おかげさまで、今では「I like C++ : )」とまで言えるようにまでなりました。 今回の連載では、 この筆者の実経験をもとに、 既に Java で OOP を理解・実践されている方(※)へ向けた C++ の学習ポイントをお送りしていきます。

※ したがって、本連載では 「オブジェクト指向のメリット」ですとか、 「ポリモーフィズムとは何ぞや?」といった話題は一切扱いません。 これらの話題・知識は既に知っていることを前提として進めさせて頂きます。

2. 開発環境の準備

さて、長い前置きとなってしまいましたが、 ここからは実際に手を動かしていきます。 今回は、「Hello World プログラム」を動かすだけですが、 その前に開発環境を用意しなければなりません。 Java でプログラミングをする初めの一歩が JDK(Java Development Kit) を用意することであるのと同様に、 C++ プログラミングを始める前にも必ず用意しなければならないものがあります。 コンパイラです。 今回の連載では Windows 上で無料で利用できる 「MinGW(Minimalist GNU For Windows)」 というフリーのコンパイラを利用します。

ダウンロードページ(http://www.mingw.org/download.shtml) から、Windows 用のインストールファイルをダウンロードして下さい。

※ 執筆時点(2004 年 2 月)では MinGW-3.1.0-1.exe というファイルが最新版です。

ダウンロード終了後、同ファイルを実行するとインストールが開始されます。 インストールフォルダを指定する以外は、全て「Yes」や「Next」を押せばよいだけですので、 難しい箇所はないかと思います : )。

さて、インストールが無事おこなわれたか念のため確認しておきましょう。

コンパイルのための 実行ファイル g++.exe は、インストールフォルダ下の bin フォルダに存在します。 例えば、C:¥MinGW というフォルダにインストールしたとすると、C:¥MinGW¥bin フォルダ内に実行ファイルが格納されています。 コマンドプロンプトから –version というオプションを引き数にして、上記ファイルを実行してみてください。

D:¥>workspace C:\MinGW\bin\g++ --version
g++ (GCC) 3.2.3 (mingw special 20030504-1)
Copyright (C) 2002 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

上記のようにバージョン確認メッセージが出力されれば、インストールは無事成功です。

ただし、コンパイルの度にいちいち絶対パスを打ち込むのは面倒ですから、 環境変数 PATH に 上述の bin フォルダ(先ほどの例では C:¥MinGW¥bin) を追加しておきましょう(*)。 これにより、どのフォルダからも g++ と打つだけでコンパイルができるようになりました。

※ Java プログラマには PATH の追加方法の解説なんて釈迦に説法、ですよね?

3. Hello C++

さあ、ようやく準備が整いました。 今回はお馴染みの「Hello World プログラム」を通して C++ における開発方法の基礎を学びましょう。

ソースコード

Java では、画面に文字列を表示するプログラムは、

ソースコード 1 : Java 版 Hello World [Test.java]
// Test.java //

public class Test {
  public static void main(String[] args) {
    System.out.println( "Hello, Java !!" );
  }
}

といった感じになりますが、C++ では下記のようになります。

ソースコード 2 : C++ 版 Hello World [Test.cpp]
// Test.cpp //

#include <iostream>
using namespace std;

int main()
{
    cout << "Hello, C++ !!" << endl;
}

上記のコードを貴方のお気に入りのエディタで記述して、Test.cpp として保存してください。 “.java” という拡張子が Java のソースコード であることを意味するのと同様、 “.cpp” という拡張子は C++( C Plus Plus )の ソースコードであることを意味します。

コンパイル & 実行

ソースコードの解説に入る前に、まずはプログラムをコンパイル & 実行させてみましょう。

Java では、

D:&yen;workspace javac Test.java <- コンパイル

D:&yen;workspace dir
Test.java  Test.class        <- Test.class というクラスファイルが生成されている

D:&yen;workspace java Test       <- JVM を起動して、Test.class を読み込ませる
Hello, Java !!

C++ では、

D:&yen;workspace g++ test.cpp    <- コンパイル

D:&yen;workspace dir
a.exe  test.cpp              <- a.exe という実行ファイルが生成されている

D:&yen;workspace a               <- a.exe を実行
Hello, C++ !!

となります。 どちらもコンパイル→実行という手順は変わらないのですが、 コンパイルの成果物、および実行方法には大きな違いがあります。

ご周知の通り Java では、 ソースコードをコンパイルするとクラスファイルが生成されます。 プログラムを動かすには、 JVM を起動して実行させたいクラスファイルを読み込ませます。

これに対して、 C++ ではソースコードをコンパイルすると、実行ファイルそのものが生成されます。 Java とは異なり Virtual Machine が介在しませんから、 各 OS 毎にコンパイルしなければなりません。 したがって、今回作成した a.exe というファイルは 他の OS 上では実行できません。

comple java
comple c++

なお、g++ コマンドはデフォルトでは、 a.exe という名称で実行ファイルを生成してしまいます。 生成される実行ファイルの名称を変更したい場合は、 -o オプションを利用しなければなりません。 例えば、Test.exe という名称で実行ファイルを生成したい場合には、 下記のようにコンパイルしてください。

D:&yen;workspace g++ -o Test.exe Test.cpp <- コンパイル

D:&yen;workspace dir
Test.exe  Test.cpp                    <- Test.exe という実行ファイルが生成されている

D:&yen;workspace Test                     <- Test.exe を実行
Hello, C++ !!

4. プログラムの入り口

Test.cpp を見た時点で既に気づかれるいる方も多いと思いますが、 Java でも C++ でも、 プログラムの実行コードは main() 内に記述します。

main [ Java 版 ]
  public static void main(String[] args) {
    //----------------------------------//
    // ここに書かれたコードが実行される //
    //----------------------------------//
  }
main [ C++ 版 ]
  int main() {
    //----------------------------------//
    // ここに書かれたコードが実行される //
    //----------------------------------//

    return 0;  // プログラム終了
  }

ただし、C++ では Java とは異なり main() の返り値が int 型(※)ですので、 プログラムを終了する箇所に return 文を記述する必要があります。 (記述しないとコンパイラに怒られます。) なお、返り値の値は、 プログラムが正常終了する場合は 0、 何らかの理由により異常終了する場合には 0 以外を返す、 という決まりになっています。 これは Java における System.exit(int status) メソッドの引き数の値と同じですね。

※ int 型などの データ型については次々回詳しく取り上げます。 現時点では、「C++ でも int 型や void 型が使えるんだなぁ。」程度に認識しておいてください。

また、返り値だけでなく引数にも違いがあります。 Java では String クラスの配列を引数にとることで、 ユーザからの引数受け付けが可能になっています。 これに対し C++ では main() には引数がありません。 それでは C++ ではユーザからの引数を受け付けることが出来ないのでしょうか? いいえ、ご安心ください。 C++ では

  • ユーザからの引数を受け付けない main()
  • ユーザからの引数を受け付ける main()

の 2 種類の main() から好きな方を選択できるのです。 今回ご紹介した main() は、 前者のユーザからの引数を受け付けない main() だったわけです。 後者のユーザからの引き数受け付けが可能な main() については、 連載を進めていく過程でまたあらめてご紹介したいと思います。

ところで、この main()、実は Java と C++ では呼び方が変わります。 Java の場合は main メソッドと呼びますが、 C++ では main 関数と呼びます。 この「関数」とは一体何者なのでしょうか? メソッドと同義と捉えてよいのでしょうか?

5. メソッド と 関数

平たく言ってしまえば、関数とは 「与えられた情報(引数)をもとに、何らかの計算をおこなって、(必要があれば)結果を返す一連の処理」 です。 つまり、Java におけるメソッドと同じ概念といえます。 しかし、厳密には両者の間には大きな違いがあります。 その証拠に、 Test.cpp における main 関数は Java の仕様では決して許されない方法で定義されています。 そうです。C++ の main 関数はクラスの中で定義されていないのです。

ご周知の通り、Java のメソッドは必ずクラスの中で定義しなければなりません。 これに対し、C++ の関数は main関数のように、クラス外でも定義可能なのです。 ちなみに、 クラスの外で定義されている関数のことを「グローバル関数」、 クラス内で定義されている関数のことを「メンバ関数」と呼びます。

したがって、「C++ のメンバ関数 == Java のメソッド」となります。 グローバル関数は Java には存在しない概念なので戸惑うかもしれませんが、 「いつでもどこからでも呼び出せるメソッド」と捉えれば OK です。 また、グローバル関数と同様に、クラス外で定義可能な 「グローバル変数」も C++ では許されています。 (クラス内で定義された変数は「メンバ変数」と呼びます。) これらグローバルな変数、関数は、 わざわざインスタンスやクラス越しに利用する必要がないので、一見すると便利そうです。 しかし、カプセル化を破壊することに繋がるため、安易な利用は禁物です。 例えば、下記のコードのように、グローバル変数・関数だけでもプログラムすることは可能ですが、 これはまさに手続き型プログラミングであり、 何のためのオブジェクト指向言語なのか分からなくなってしまいます。

ソースコード 3 : グローバル変数・関数を用いたプログラム例 [GlobalTest.cpp]
// GlobalTest.cpp //
/*
 * C++ ではこのように
 * グローバル変数・関数のみを利用してプログラミングすることもできます。
 * しかし、これではオブジェクト指向言語を使う必要性が全くないので、
 * こういったコードは書かないようにしましょう
 *
 * この例ならば、Counter クラスをきちんと用意するべきです。
 */

#include <iostream>
using namespace std;

/**
 * カウンター値(グローバル変数)
 */
int counter = 0;

/**
 * カウンター値を 1 つ増やす(グローバル関数)
 */
void incrementCounter()
{
  counter++;
} 

int main()
{
    cout << "Counter Value : " << counter << endl;  // 「出力」については次回取り上げます

    incrementCounter();

    cout << "Counter Value : " << counter << endl;
}

ちなみに、コメントの書き方ですが、

/*
 * コメント
 */

~~cpp // 一行コメント ~~~

の 2 通りのスタイルが利用可能です。

6. まとめ & 次回予告

いかがでしたでしょうか? 以上で、新連載「Java プログラマに贈る C++ 入門」の第一回目は終了です。 タイトルを見て、 「Java 全盛の時代に何故今更 C++ ?」とか、 「『C++ プログラマに贈る Java 入門』 の間違いでは?」、 と思われた方も多いのではないでしょうか? しかし、冒頭部分で触れましたように、 現在でも C++ によって開発をしなければならない / した方がよい 案件は数多く存在します。 その一方で、 Java からこの業界に入ってくる人がますます増えてきているのもまた事実です。 そういった方々が、ある日突然 C++ を使うことになったときの ガイドラインの 1 つになれば、という考えで 今回連載記事を執筆させて頂くことになりました。

さて、今回は「Hello World プログラム」を通して、

  • コンパイル & 実行方法
  • main 関数
  • メソッドと関数の違い

についてご紹介しました。しかし、まだ

  • #include
  • namespace
  • 出力方法

に関して全く触れていませんので、 次回はこれらの話題について扱っていきたいと思います。 それでは近いうちにまたお会いしましょう。
See you later.