第七回レポート総評




[レポート課題 2] (2) private なメンバにアクセスしたときのエラー

エラー E2247 W:\pg2\07\complex_test.cpp 8:
'myComplex::x'  はアクセスできない(関数 main() )
エラー E2247 W:\pg2\07\complex_test.cpp 9:
'myComplex::y'  はアクセスできない(関数 main() )
エラー E2247 W:\pg2\07\complex_test.cpp 11:
'myComplex::x'  はアクセスできない(関数 main() )
エラー E2247 W:\pg2\07\complex_test.cpp 12:
'myComplex::y'  はアクセスできない(関数 main() )


ファイル名、フォルダ名、行数は人によって異なるでしょうが、 大体上記のようなエラーがでます。
理由は「プライベートなメンバにアクセスしようとしたため」です。 わからない人は資料を復習しておいてください。

なお、上と異なるエラーが出ている人は、別の原因でエラーが出ているはずです。 プログラムの書き間違いがないか、チェックしておきましょう。

ところで、資料では myComplex.h と myComplex.cpp に myComplex クラスを定義 し、ファイル名とクラス名を一致させていました。
これは、わかりやすくするためにそうしただけであり、実は クラス名 (myComplex) と、それを記述するファイル名は一致する必要はありません。

だから、例えばクラス名を「myComplex」に固定し、 ファイル名を「myComplex01.cpp (h)、myComplex02.cpp (h)、 …」 などと変更していっても構いません。
# ただし、ヘッダの読み込み「#include "myComplex.h"」の部分も 適切に変更しなければならないこと、
# プロジェクトに属するファイルが正しいか、などに注意しないとハマることになります

さらに、一つのファイルに複数のクラスを定義しても構いません。

# なお、余談ですが Java 言語では、ファイル名とクラス名は一致していなければなりません。


[レポート課題 2] (4) complex_test.cpp の内容

#include <iostream>
#include "myComplex.h"
using namespace std;

int main(void){

	myComplex c;
	myComplex *cp;

	c.setReal(3);
	c.setImag(4);

	cp = new myComplex;
	cp->setReal(0.5);
	cp->setImag( sqrt(3)/2 );

	cout << "norm of c is " << c.norm() << endl;
	cout << "norm of cp is " << cp->norm() << endl;

	cout << "c=" << c.getReal() << "+" << c.getImag() << "i"<< endl;         /********変更点********/
	cout << "cp=" << cp->getReal() << "+" << cp->getImag() << "i"<< endl;   /********変更点********/

	delete cp;
	return 0;
}


これはよくできていたようです。


[レポート課題 1] クラスの例

長くなりそうなので、これを一番最後に回しました。

いろいろ面白い例がでてきたので、一部例をあげてみましょう。

[携帯電話クラス]

データメンバ:電源の状態、電波の状態、着信設定、着信音量、キーロックの状態、等

メンバ関数:電源 ON/OFF、アンテナの探索、バイブ ON/OFF、音量調節、キーロック ON/OFF、等


資料にテレビクラスの例をあげたので、電化製品の例をあげた人が多かったようです。
上記の携帯電話クラスは、内容的にもほぼ問題ないと思います。

いくつか補足しておきましょう。
もちろん、携帯電話の内部のアプリケーションが実際に C++ で書かれているわけではありません。
しかし、実際に携帯電話を操作することを 「メンバ関数呼び出し」→「メンバの状態変更」のようにとらえることは クラスを理解する上で有効だと思います。

また、さらにメンバを追加するなら、 データメンバには「通話状態」、「ネット接続状態」、「メール最大記憶容量」、「現在のメール数」 など、
それに対応するメンバ関数には「通話」、「ネット接続」、「メール取得」 など、いくらでも考えられます。

また、メンバ関数の働きを考えると、「通話中にメールが来たらどうするか」、 「メールを取得したときにメール最大記憶容量を超えたらどうするか」 など、
考慮しなければならないことが膨大にあることに気がつくでしょう。

最近は携帯電話の新製品が出るたびに、バグによる回収騒ぎが話題になりますが、
携帯電話の複雑化が進むとそのようなトラブルが増えるのはやむを得ないのかもしれません。

[プレイステーションクラス]

データメンバ:電源の状態、ゲーム or DVD、ネット接続状況、メモリカードの状態、コントローラ

メンバ関数:電源の ON/OFF、挿入する ROM を変える、モデムの接続、メモリカードの挿入、コントローラの挿入


次の例はプレイステーションです。
携帯電話の例のように、プレイステーションの内部に「プレイステーションクラス」 があると考えてみましょう。
# もちろん、実際にプレイステーションの内部が C++ で書かれているわけではありません。

データメンバは問題ないと思いますが、メンバ関数の「挿入する ROM を変える」、 「モデムの接続」、「メモリカードの挿入」、「コントローラの挿入」は
どれも「人間が行う行為」であるので、プレイステーションクラスのメンバとしては 不適切に思えます。

「ROM のチェック (有/無、Game/DVD)」、「モデム状態のチェック」 「メモリカードの状態のチェック」、「コントローラのチェック」 などに変更すれば、よりもっともらしくなるでしょう。
ROM のチェックが行われ、ゲームの CD が入っていれば、ゲームが起動される、というわけです。

[天気]

データメンバ:雲量、気温、湿度、気圧、風量

メンバ関数:気象予測、本日の天気


次は電化製品から離れて「天気」クラスです。
ほぼ問題ない気がしますが、「天気」クラスという名前だと、 「自然現象そのもの」をクラス化しているような印象を受けてしまいます。

# 実際には自然現象そのものを記述するのは不可能であり、自然現象に対する記述はその現象に対する何らかのモデルとなると思います。

ですから、クラス名は「気象モデル」クラス、あるいはもっと割り切って「天気予報」クラスにした方が良いかも知れません。

「天気予報クラス」にした場合、メンバ関数に 「現在の気象状態取得」、「(現在の気象状態に基づく) 気象予測」、 「予測と実際の気象状態との比較」などがあるともっともらしいでしょう。

これと同じ考えにもとづき、「株価予測クラス」、「時系列予測クラス」 などが考えられます。
これらは実際にプログラミング出来そうです。

[カレークラス]

データメンバ:ジャガイモ、にんじん、タマネギ、肉、カレー粉

メンバ関数:材料を洗う、材料をむく、材料を切る、炒める、煮込む


最後はカレークラスです。さすがにこれはプログラミングからは かけ離れているので、クラスと対応させるのはなかなか難しそうです。
しかし、「プログラミングできるかどうかは考えなくても良い」 と書いてしまった以上、ちょっと考えてみることにします。

まず、カレーには「材料をそろえた状態」、「材料を炒めている状態」 …「完成した状態」、「一晩寝かせてコクが増した状態」、「もう食べられない状態」 など、様々な状態が考えられます。
それらを表す一つのデータメンバ「現在のカレーの状態」があった方がよいでしょう。
このように系の状態を表す変数はしばしば「フラグ」と呼ばれます。

「材料を洗う」、「材料をむく」…などのメンバ関数を適切な順番で呼び出すことで 「現在のカレーの状態」は変化していきます。
メンバ関数呼び出しの順序を間違えると、エラーがでる、という感じでしょうか。

難しいのは「材料」を表すデータメンバをどうするか、という点です。
カレーの種類によって、材料は変化するからです。

一つ思いつく例は以下のような感じです。
まず「材料」という抽象的なメンバの配列 (ポインタ) を 用意しておき、抽象的なカレークラスを作成します。
それを継承 (派生) させることで「チキンカレークラス」、 「野菜カレークラス」などを実現します。
そのためには、「じゃがいも」、「にんじん」などが 「材料クラス」を派生させたクラスで実現されていれば良さそうです。
これはオブジェクト指向の「多態 (Polymorphism)」という考え方に 関連してきますが、これは演習の範囲を超えているのでここまでにしておきます。


クラスの例 (研究に結びつきそうな例)

以下、研究に結びつきそうなクラスの例を書いておきます。
細かな解説はつけませんので、興味のある人は考えてみるのも面白いでしょう。

[(白黒) 画像クラス]

データメンバ:画像の幅、画像の高さ、ピクセル値を表す配列 (ポインタ)

メンバ関数:幅と高さにもとづく配列の領域確保 (コンストラクタ)、画像ファイルからピクセル値を設定、
            輝度取得、コントラスト取得、エッジ抽出、2 次元フーリエ変換、2 次元 wavelet 変換、等


[ニューラルネットワーククラス]

データメンバ:ニューロンの個数、ニューロンの配列 (ポインタ)、シナプスの配列 (ポインタ)

メンバ関数:ニューロンの個数に基づくニューロン配列とシナプス配列の領域確保、
            学習 (強化学習、自己組織化学習、etc)、等

※ ただし、「ニューロンクラス」、「シナプスクラス」も別途用意しなければならない            





C から入る C++ に戻る