ぎょーむ日誌 2000-08-06
2000 年 08 月 06 日 (日)
- 1030 起床.
晴れ.
- 朝飯食いながら,
早朝の懸案であった
「リンク時のエラー」
を解消しようとする.
- うえ.
コーヒー変な味.
あ,
そうか.
先日このマグカップで干しシイタケを
戻してしまったんですよね.
シイタケフレイヴァーのコーヒー.
貧乏なのでガマンして飲む.
- やはり単純なエラーだったと判明.
よーし,
問題なく動作するな.
「ぎょーむ日誌」
に昨日の作業の概要まとめる.
自分でもすぐに忘れてしまうからね.
よし,
次はコマンドラインオプションの
引数処理部のクラス化だ.
- もともと Forest とか Aqua といった
「世界」クラスの一部であった
処理関数をあーだこーだとヒネくってみる.
- ヒネくってるうちに,
これはひょっとして
……
今まで使ったことない
禁断の技法「継承」(inheritance)
の使いドコロではなかろうか
…… ?
という考えが浮かんでくる.
- 継承とは,
まあ,
以下のようなモノです
(継承の動作確認のために
作ったサンプルコード).
#include <iostream>
// (1) 基底クラス Tree の定義 --------------------------------------
class Tree {
private:
double dbh;
public:
Tree( void ) : dbh( 5.0 ) { ; } // 初期値なしのコンストラクター
double Dbh( void ) { return dbh; }
void InputDbh( const int& new_dbh ) { dbh = new_dbh; }
};
// (2) 派生クラス Acer の定義 --------------------------------------
class Acer : public Tree { // Acer は Tree から継承されている
private:
// Acer 固有の変数とか
public:
Acer( void ) { ; } // 初期値なしのコンストラクター
Acer( const double& dbh ) { // 初期値を指定するコンストラクター
this->InputDbh( dbh );
} // Tree クラスの InputDbh 関数を呼び出している
};
// (3) 試験運転用の main 関数 --------------------------------------
int main ( void ) {
Acer acer1, acer2( 15.0 ); // Acer 型の変数 acer の宣言
cout << "acer1 (before input): dbh = " << acer1.Dbh() << endl;
acer1.InputDbh( 10.0 ); // Acer ではなく Tree の関数を呼び出してる
cout << "acer1 (after input) : dbh = " << acer1.Dbh() << endl;
cout << "acer2 (initialized) : dbh = " << acer2.Dbh() << endl;
return 0;
}
- 上の例では,
まず原型とでもいうべき Tree クラスというのを定義してる.
つぎに,
この Tree を継承した Acer クラスを定義している.
継承とは何とも大げさな語だけど,
上をみればわかるとおり
「Tree にオマケを付け足して Acer にする」
「Tree にあれこれ上塗りして Acer にする」
という程度のことなのである.
Tree の属性と機能は Acer に引き継がれている.
- Tree を継承できるのは Acer だけでなく,
Betula とか Carpinus だとか
いろいろな派生されたクラスを作ってよい.
- 試験運転用の main 関数について簡単に.
まず Acer クラスに属する
(Acer 型をもつ)
acer1 と acer2 を宣言してる.
acer1 は初期値なし,
acer2 は 15.0 という初期値をもつ.
実行結果はこうなる.
acer1 (before input): dbh = 5
acer1 (after input) : dbh = 10
acer2 (initialized) : dbh = 15
- acer1 は初期値なしなので,
Acer( void ) のコンストラクターが呼び出される.
これは { ; } という空のブロックを持つだけなので,
何もしない関数であるかのように見える.
ところが,
結果を見れば
dbh = 5.0 という値が入っていることがわかる.
Acer( void ) のコンストラクターが呼ばれると,
Tree( void ) のコンストラクターも呼び出されていることが
わかる.
- cout で acer1.Dbh() 表示されたあと,
Tree クラスのメンバー関数 InputDbh で
dbh の値が書き換えられて,
その結果が表示されている.
- acer2 の宣言では初期値 15.0 が指定されている.
ところが Tree クラスには
初期値を指定するコンストラクターはない.
しかし Acer クラスには
そういうコンストラクター
Acer( const double& ) が
定義されているんで,
そちらが呼び出されているんである.
動作の途中の状態を調べてみると,
この場合でもまず Tree( void ) が呼ばれている,
とわかった
(結果を見てもそれはわかんないけど).
したがってこの場合はまず dbh = 5.0 が
代入されたあとに,
Acer( const double& ) コンストラクター内の
this->InputDbh() によって
dbh = 15.0 と書き換えられているわけだ.
- はあ,
このぐらい簡単な例だとわかりやすいけど,
クラスが増えてきたりややこしい構造もっている場合には,
継承が原因になって
呪われきったコードとかができてしまいそう
……
- 話はだいぶんそれたけど,
(コマンドラインオプションを管理してくれる)
Option クラスというのを
(BEGIN-END 構造あるテキストファイルを読み込んで
データーベイス化しちゃう)
Filereader クラスから継承して作ってはどうか,
という
やや正気ではないアイデアを
思いついてしまったんである.
ふふふふふ.
えーと,
Filereader のほうが基底クラスで
Option をその派生クラスにしよう,
ということですね.
- というのも,
Filereader はいまや「型なし」クラス Unival
を「持つ」
(「持つ」は継承ではない),
かなり強力な入力処理システムになりつつある.
一方で
「コマンドラインオプションの処理とは何か?」
と考えると
……
その入力は「一行」ですまされるものの,
内容はと言えば
bool 的なスイッチがあったり,
ファイル名指定したり,
数値を変更したり,
とごちゃごちゃしたシロモノに他ならない.
問い合わせのほうも
「--verbose はオンになってる?」
とか
「--input_dir 指定されてる?
されてたらディレクトリー名教えて」
とか,
そういう雑多なモノでしょ.
- そこで,
Option クラスは Filereader を継承して
定義することとし,
ただしコンストラクターの中で
指定されたオプションをすべて
テンポラリーファイルに書き出してから
(これはあまりスマートではなく,
テンポラリーなストリームに書き出すべきだろう),
Filereader の読み込み関数に
それを読み取らせていく.
あとは Filereader と同じように
Option クラスのオブジェクトに
問い合わせを発して
必要な型の戻り値を受け取ればよい.
- という方針大転換のもと,
コードを書き換えて日曜日の午後はすぎていく.
- 1600 継承で定義した Option クラスがコンパイルできた.
一区切りついたんで,
大森東図書館に本を返しにいく.
また 6 冊の本と CD 借りる.
1650 帰宅.
[近所の八百屋]
自宅から歩いて一分のところに
ある八百屋.内川の横に位置す
る.今日は写真だけ.
- 遅い昼飯
(というか第二食というか)
を食って,
またコード書きに取り組む.
ライブラリーのほうは一通りできてるんで,
これを利用するプログラムのほうを改造.
例によって PipeTree の
forest_constructer.cc に大手術が施される.
- ときどきコンパイルしてみるんだけど
……
あああああ,
PipeTree みたいな ``STL 太り'' しちゃった
莫迦でかコードを
愛機 ThinkPad560E (Pentium 166 MHz) で
コンパイルすると
もう遅くて遅くて気絶しそう.
- いや,
もちろん make で分割コンパイルして,
なお,
ですよ.
だいたい,
ソースファイル間の依存性がみょーに強いんで,
ちょっといぢると
直ちに全コンパイルしやがるのである.
- とりあえず,
Forest クラスから
コマンドラインオプション関係の
だーてぃーわーくコードを削除することに成功.
- ひといきついて,
週末にやるべき雑用の一つにイヤイヤ取り組む.
- 運転免許証記載事項変更届の発送.
いやあ,
まだ免許証の住所を書き換えてなかったんですよね.
しかし,
大森署もヒドイんですよ.
平日の 0900-1700 しか窓口が開いてなくてですねえ.
免許証のために半日休むのもなあ
(まぁ,
UQ というのは 1 時間単位でコマギレに
申請できるようなんだけど).
- 警察のいいなりになるのはイヤなんで,
郵送でなんとかならないかという試行である.
ああ,
うまくいくだろうか.
- えーと,ネットで調べると,
大森警察署の住所は
……
〒143-0014
大田区大森中一丁目1番16号
(電話番号 03-3762-0110)
……
と.
- 封筒に,
顔写真つき変更届の書類
(これは以前に時間外に無理矢理かっぱらってきた),
運転免許証,
住民票,
切手つき返信封筒をいれる.
うーん,
いちゃもんつけられて reject されそうだ.
- 2230 散歩がてら近所のポストに投函にいく.
ついでにゴミ出し.
明日の朝はゴミ回収なんで.
- 他にもやるべき雑用はあるんだけど,
心身にわるそうなんで,
Option クラスの改良作業にもどる.
- もうひとつだけ付け加えたいのは,
エラー処理とヘルプを統合したような
機能である.
- 時刻すでに 0130.
そろそろ寝なくては.
0150 ようやくヘルプに関してはうまくいく.
これをエラー処理と結合するのは
明日にしよう.
進行は比較的順調ではあるんだが.
- 研究所の腐れサーヴァーどもにバックアップ取るのは
すごく大変なので,
いつものごとく<鳳翔> に必要最小限送る.
- 今日の食卓
- 朝 (1100):
スパゲッティー.
ソースは昨晩の炒めものを流用.
- 昼 (1740):
ニンジン・タマネギ・ナスの炒めもの.
今日は味噌・砂糖で味つけ.
ナス味噌らしきものを実現しようとするも,
似ても似つかぬ代物に.
- 晩 (2130):
昼の残り.