DATE : 2006/10/22 (Sun)
Java では、throw 文を使って例外を投げることができます。(例では、NullPointerException を投げています)
throw new NullPointerException();
そして、catch 文で例外をキャッチできます。(例では、function メソッドで発生する NullPointerException をキャッチします)
try { function(); } catch (NullPointerException e) { // 例外用の処理 }
C++ にも例外機構があります。Java の場合は java.lang.Throwable を継承しているクラスのみ投げることができますが、C++ の場合はどのような型でも例外オブジェクトとして送出することができます。
例えば、次のコードは、例外オブジェクトとして int 型の1を送出します。
throw 1;
この例外を受け取るコードを書くと、次のようになります。この例では、function 関数の中に上の throw 文があるものと仮定しています。
try { function(); } catch (int e) { // 例外用の処理 }
受け取った値を使用しない場合は、変数名(上の例では「e」)を省略できます。
オブジェクトを送出することもできます。
try { throw Object(); } catch (Object& e) { // 例外用の処理 }
ここで、Object オブジェクトは new で生成しないようにします。new で生成してしまうと、生成したオブジェクトを解放し忘れてしまう場合があります。
また、受け取るときは参照で受け取るようにします。
なお、catch 文を複数連ねると、複数の例外に対応できます。つまり、投げられた例外に応じた catch 文が呼び出されます。
ちなみに、次のようにすると、どのような型でも受け取ることができます。
try { function(); } catch(...) { // 例外用の処理 }
(;^ω^)Java の catch(Exception e) { } のようなものですね
なお、catch 文の中で次のように throw 文を記述すると、受け取ったものと同じ例外を送出することができます。
try { function(); } catch(int e) { // 例外用の処理 throw; }
(;^ω^)Java の場合は、catch (Exception e) { throw e; } ですね。
なお、例外機構によって呼び出し元の関数に戻っていく過程では、スタックが次々と巻き戻されていきます。その際、スタック上に確保されていたオブジェクトは解放されますが、ヒープ上に確保されていたオブジェクトは解放されません。そのため、呼び出し元に戻る過程にあるヒープ上のオブジェクトは、上の方法を使って解放するようにします。
Object* obj = new Object(); try { function(); } catch(...) { // 受け取った例外は呼び出し元に投げる delete obj; throw; }
なお、標準 C++ ライブラリには、std::exception という、例外を表すオブジェクトがあります。
(;^ω^)こちらは、Java の Exception (RuntimeException)クラスのような働きをしてくれます。ちなみに、Java のような finally 文はありません。また、チェック例外もありません。
参考文献
- C++編(言語解説) 第25章 例外機構
- C++ プログラミングガイド 5.例外処理
- C++ の例外処理について
- Hey! Java Programming! C++言語 例外処理
- C++編(標準ライブラリ) 第27章 例外クラス
DATE : 2006/10/16 (Mon)
C++ には、使用目的に応じた4種類のキャストがあります。
加えて C 言語形式のキャストも使用できますが、キャストの使用目的が不明瞭になるため推奨されていません。
C++ のキャストは以下の種類に分かれています。
- static_cast
- reinterpret_cast
- const_cast
- dynamic_cast
static_cast を例にとると、次のように使用します。
double d = 2.5; int i = static_cast<int>(d);
「<>」の間にキャスト先の型を入れ、「()」内にキャスト対象の値などを入れます。
以下に使い方を簡単にまとめます。
- static_cast
- 暗黙の型変換が存在する場合に使用するキャストです。例えば、int と double 間や継承関係を持つクラス間のポインタ、参照に使用できます。また、void 型ポインタから具体的な型のポインタへ、int 値から列挙型への変換にも使用できます。
- reinterpret_cast
- 型だけを単純に変更し、内部のビット列は変更しない場合に使用するキャストです。具体的には、ポインタ型同士の変換に使用します。
- const_cast
- ポインタや参照の const 修飾子、volatile 修飾子を外すためのキャストです。
- dynamic_cast
- 仮想関数のある継承関係を持つクラス間のポインタ、参照の型変換を動的に行うためのキャストです。 static_cast とは違い、型変換が行えない場合はキャストの結果が0(ヌル)となります(参照の型変換の場合は、std::bad_cast 例外が発生します)。なお、基底クラスに仮想関数がない場合は、dynamic_cast は使えません。
参考文献
DATE : 2006/10/14 (Sat)
(前回の記事)
テストケースの基本
テストケースは、CppUnit::TestCase(UnitTestCase.h)を継承したクラスに記述します。
また、次のメンバ関数をオーバーロードします。
- void setUp()
- テストケースが実行されると呼び出される関数です。この関数で、このテストケース全体の準備を行います。なお、省略可能です。
- void runTest()
- setUp メンバ関数による準備が終わると呼び出される関数です。実際のテストは、この関数に記述します。しかし実際は、テスト要素ごとに作ったメンバ関数を runTest から呼び出す形になると思います。
- void tearDown()
- runTest メンバ関数が終わると呼び出される関数です。この関数で、テストケース全体の始末を行います。setUp と同様に、省略可能です。
なお、他にも、テストケースに名前をつけるためのコンストラクタなどもありますが、ここでは省略します。
それぞれのテストでは、テスト対象クラスの public / protected メンバ関数からの結果と想定した結果との比較を行うことで、正しく処理を行ったかどうかを確かめます。比較には、次のマクロ関数を使用します。
- ASSERT_EQUALS(想定, 実際)
- 想定した値と実際の値とが等しい(==)かどうか比較します。
- ASSERT_EQUALS_DELTA(想定, 実際, 誤差)
- 上のものと同じですが、誤差を定めることができます。
- ASSERT_EQUALS_OBJ(想定, 実際)
- オブジェクト同士が同じもの(==)かどうか比較します。
- ASSERT_TRUE(実際)
- 実際の結果が真かどうかを確かめます。ただし、引数に渡せるのは bool 型です。BREW で真偽を表す boolean 型は、ASSERT_EQUALS で比較します。
- ASSERT_NULL(実際)
- 実際の結果がヌルであることを確かめます。
- ASSERT_NOT_NULL(実際)
- 実際の結果がヌルではないことを確かめます。
- FAIL_MSG(文字列)
- このマクロが実行されると、テストは必ず失敗します。到達してはならない部分にこのマクロを記述します。失敗した際のメッセージとして、文字列を渡すことができます。
なお、ASSERT_* のそれぞれには、失敗時にメッセージを表示するためのマクロもあります。ただし、ここでは省略します。
(づづきます)
DATE : 2006/10/13 (Fri)
テスト用プロジェクトの作成
解凍して出てきたフォルダのうち、src フォルダの中にあるファイルを、テスト用のプロジェクトフォルダにコピーします。ただし、次のようにコピーします。
- src フォルダの直下にあるファイル(フォルダは除く)をコピー
- src\utils フォルダをコピー
テスト用のプロジェクトファイルを「test_project」とすると、コピー後は次に示すフォルダ階層になるはずです。
- test_project
- src フォルダの直下にあったファイル
- utils フォルダ
次に、src\platforms\brew フォルダの中身を、プロジェクトフォルダにコピーします。ただし、brew フォルダの中にはサンプル用のファイルも含まれているので、C++ のソースコード(*.h と *.cpp)のみをコピーします。なお、その中にある brewunit.cpp はサンプル用のソースコードです。これを基にしてテストプログラムを記述すると楽なので、コピーすることにしました。
結果、プロジェクトフォルダは次のようなフォルダ階層になります。
- test_project
- src フォルダの直下にあったファイル
- src\platforms\brew フォルダの直下にあったソースコード
- utils フォルダ
もしも Visual C++ を使っている場合は、フィルタを作成してこれまでにコピーしたファイルをまとめておくと見通しが良くなります(ただし、brewunit.cpp はテストプログラムの作成の際に参照するだけなので、フィルタにはまとめないようにします)。
(つづきます)
DATE : 2006/10/12 (Thu)
C++ 用の、しかも BREW に対応したテスティングフレームワークがないかとネット上をさまよっていたら、その名も「Brew Test Unit」なるものを見つけました。
Brew Test Unit では、テストを行う BREW アプリケーションを実行してテストを行います。テスト結果は BREW シミュレータの出力ウィンドウに出力したり、ログファイルに書き出したりできます。BREW アプリケーションとしてテストできるので、BREW API に依存したモジュールでもテストすることができます。
せっかくなので、簡単な使い方をメモしていこうと思います。対象とするバージョンは、1.0.4です。
ダウンロード
まず、「Brew Test Unit download」から、「brewTestUnit-1.0.4.zip」をダウンロードします。
ダウンロードしたファイルを解凍すると、次の一覧に示すフォルダやファイルが出てきます。
- build フォルダ
- vc71_brew フォルダに、サンプルをビルドする Visual C++ 7.1 用のプロジェクトファイルが格納されています。
- doc フォルダ
- Brew Test Unit の API ドキュメントが納められています。
- examples フォルダ
- テストケースの例が納められています。
- src
- Brew Test Unit のソースコードです。
(つづきます)