月曜日, 6月 16, 2008

クロスファイア

予定通り、クロスファイアを読みました。
長編と言う事だけあって、それなりに面白かったです。
燔祭を先に読んでいた事もあり新鮮さについては足りませんでしたが
燔祭での出来事がクロスファイアの中にも登場し
話として繋がる場面も多々ありました。

必要悪と言う事がテーマのような気もしましたが
個人的には必要悪はあるのではないかという考えを持っています。
かと言って、何が必要悪であるかの線引きは難しいところもあるのですが
先週、事件となった秋葉原の犯人が捕まっていない状況で
その犯人が再犯を犯す前に、何かした場合、自分がどう考えるかと言えば
しょうがないと考えてしまう気がします。
かと言って、それでは犯人と同じ事をしていると言われればそれまでです。
人の考え方ですので、どちらが正しいと言う事はないのかもしれませんが
いろいろと考えさせられるテーマである事は間違いありません。

木曜日, 6月 12, 2008

先週の競馬

ウォッカが勝ちましたね。
それも予想以上の圧勝でした。
ヴィクトリアマイルと比べると、ジョッキーの今年の活躍が
そうさせたかのように感じてしまいます。

結果から言えば、ヴィクトリアマイルの時もさっさと抜け出して
後は特有の勝負根性で競り合えば勝てたのかもしれませんね。
それにしても強い競馬だったと思います。

ダイワスカーレットへの挑戦権を再度手に入れたってところでしょうか?
次の対決は秋の天皇賞って事になると思います。
チューリップ賞のようなマッチレースを見るのが希望ですが
どうでしょうかね。

土曜日のユニコーンSを圧勝した馬は端午Sで
サクセスブロッケンにぼろ負けした馬です。
ダービーでどん尻となったサクセスブロッケンはダートでは
どんだけ強いんだって事を見せつけられた気がします。

路線が違うため直接対決は実現しないのかもしれませんが
カジノドライヴとの対決も見たいですね。
本当にカジノドライヴってサクセスブロッケンより強いのかな?
非常に疑問です。

カジノドライヴの回避

残念な結果となりました。
ある意味で一番最悪のスタート地点に立つ事ができずというものでした。
関係者の方は非常に無念だったでしょうね。

ビックブラウンが失速という結果だけに
勝たなくてはいけなかったような気がしてしょうがありません。

この無念は秋に晴らして欲しいですね。

金曜日, 6月 06, 2008

鳩笛草―燔祭・朽ちてゆくまで

宮部みゆきさんのクロスファイアを読もうと思ったら、
燔祭の続きと言う事なので、こちらの本を先に読みました。
短編集?中編集ですかね。だったため正直あんまり期待していなかったのが本音です。
でも、面白かったですね。

超能力系の内容を集めた小説ですね。
「朽ちてゆくまで」と「鳩笛草」は今まで出会った事のある能力ですが
(もちろん、小説やドラマですが)
燔祭の能力は斬新でした。
燔祭事態は短いし読んでみるのもお勧めします。

まあ、一番面白かったのはタイトルになっている鳩笛草ですけど。
次は予定通り、クロスファイアを読みます。

月曜日, 6月 02, 2008

ダービー

ダービーはいつものごとく競馬場で観戦をしたのですが
あまりにもの人のいなさにびっくりです。
私の周りには余裕のある空間があり、新聞を広げる事も出来たくらいです。
年々競馬の人気が陰ってきているのか、単純に今年のクラシックに魅力がないのか
私には分かりませんが、とにかく人のいないダービーでしたね。
どうすれば競馬魅力が復活するのか分かりませんが
関係者の方にはがんばって欲しいと感じた1日だったかもしれません。

クリスタルウイングはスタートしてからの1コーナーまでの位置取り、
3コーナーから4コーナーまでの進出などを見る限り
正直、もしやって思ってしまいました。
直線入ってまっすぐ走る事のできない馬と言う事を路程してしまいました。
ダービーを勝つには、精神面での成長が不足していたって事なのでしょうね。
もしかしたらGⅠに手が届く馬なのかもしれません。

レースは完全にスマイルジャックのものだったと感じてます。
それを外から強襲してしまうのですからディープスカイは
本当に強い馬なのでしょうね。
四位ジョッキーが何かやったとは思えません。
最内の馬を大外強襲させるのですから...

サクセスブロッケンの過剰人気も面白かったですね。
混戦と言う事を一番証拠として提示した内容でしたね。
私には事件以外なにものでもありません。

私の今年のPOG大逆転はこれでカジノドライブにかかってきました。
相手は強いですが期待ですね。
POG関係ないですね(笑)。
日本人として、日本馬がアメリカの3冠レースの
1つを勝つところを生で見てみたいですね。

火曜日, 5月 27, 2008

ダービーウィーク

今週は遂に日本ダービーとなります。
指名馬も何とか出走にこじつけ多少なりとも楽しみがあります。
まあ、有力馬ではありませんのでオッズもそこそこ期待できそうなので
馬券も豪快に買ってしまおうかと思ってます。
これはペーパーオーナーの特権と言っても良いかもしれません。

ペーパオーナーでなければこの馬では勝負できないと言う事も考えられますから。
というか、多くの人は押さえ候補でしょうね。

さいえんす?

東野圭吾さんのどこかの雑誌の連載を集めた内容でした。
まあ、面白いとは言いませんが面白くある必要もないような気もするので
何とも言えませんね。
これは小説とは言いませんね。
なので評価というものはできませんが、
東野圭吾ファンであれば読んでみてはってな感じです。

月曜日, 5月 26, 2008

オークス

終わってみれば、桜花賞1、2着馬と1番人気馬。
簡単なようで難しいオークスでした。

期待のリトルアマポーラはう~んって結果です。
馬が思ったより動かなかったようですが
武幸四郎さんの運みたいなものも感じますね。
GⅠでの人気馬に乗ってる武幸四郎を期待して良いのか?
って考えれば、私の中では答えは一つだったのですが...

トールポピーは強引な騎乗での勝利でしたが
あれで無ければ勝てなかった事を考えると
勝負事と考えれば良かったのかもしれません。
たしかに迷惑をかけたようにも見えましたが
それは結果ですから仕方ありませんね。

レッドアゲートも思ったより走らなかったし
なんかすっきりしないオークスだったというのが正直な感想です。

土曜日, 5月 24, 2008

虹を操る少年

ストーリーとしては好きな部類かもしれません。

今で言えば、時代を変えようと思ったら立ち上がるべき人は
変えて欲しい人であって、変える機関ではないと思います。
変える機関は、その権力、その影響力を守ろうとするため
機関不要論などど言った事については、議論が出来ないはずです。

そう言った意味では分かっていた事、分かっていたと思っていた事を
改めて再認識させられたという事が良かった小説ですね。
このような話を書くのに選んだ題材がまた新鮮でしたね。

水曜日, 5月 21, 2008

ジョッキー

松樹剛史さんの小説です。
実は初めての競馬小説で思ったより面白かったのがびっくりです。
正直、競馬の面白さはスポーツと同じで決められたストーリーがないところです。
小説上の競馬というものは、決められたストーリーを読んでいるだけですから
面白くはないと思って読み始めました。

読んでみると意外と面白く一気に読んだ感があります。
個人的には終わり方がハッピーにしろアンハッピーにしろ
もう少し何かあっただろうと思っていますが全体的には良かったと思います。
推理小説と比べても、読みやすさはありますし
競馬好きで小説嫌いという人にお勧めかもしれません。

私が競馬と見るのはやっぱり、1Rから見るときもありますが
基本的には、重賞、オープン、特別、デビュー戦などが多く
重賞やオープンでも王道を外しているようなローカルでの
重賞はそれほど興味はありません。

しかし、この小説を読むとやっぱりそこにもストーリーがあるという事を
改めて考えさせられた感じがします。

月曜日, 5月 19, 2008

武豊は乗れてない

今週は東京で土曜日、日曜日と重賞が連日あり
その両レースで1番人気馬にまたがったのが武豊ジョッキーです。
普段は武豊が騎乗する事で過剰人気になる事も多いのですが
今回の両レースについて言えば、誰が騎乗しても
1人気だったと思う馬であり、人馬ともに1番だったのではないでしょうか?

レースを見ていても、馬の仕上がりが悪かったとか
そのような事は感じられませんでした。

それでも2頭とも負けました。
私はジョッキーの問題だと思ってます。
リーディングではダントツですが、今年の重賞成績が物語っているように
中身が伴っていない気がします。
今回の2重賞も馬が伸びている事を考えると仕掛けどころなのか
捌き方なのか分かりませんが、
勝ち馬に跨った騎手との違いだったのではないでしょうか?

特に土曜日のスーパーホーネットに跨った藤岡ジョッキーとは
無心に馬の力を出す事だけを考えたジョッキーとの差を感じてしまいました。

武豊ジョッキーは間違いなく実力No1ジョッキーだと思っていますので
早く復活して欲しいものです。

犯人のいない殺人の夜

タイトルに惹かれていた本でした。
ただ、ページを開けてみると衝撃の短編集。
かるいショックから入っていった本です。
単純に短編集が好きではない私の意見ですので
意見がある人はスルーして下さい。

読んでいるときは短編集のわりに以外と面白いなと思ったのですが
読み終わって目次を見てみると
やっぱり「う~ん」って感じを否めません。

それぞれ感想を。
・小さな故意の物語
読んでいる時は引き込まれていたかもしれません。
それでも最後まで面白いとは思えませんでした。
とにかく、盛り上がる事もなく最後までたんたんと進み
意外とは言えない犯人?(って書き方が良いかは分かりません。)
こんな事で殺人までいくのかと言える動機(まあ、人の悩みなんて他人には分かりませんが)
面白いとは言えない問題は尽きない気がします。

・闇の中の二人
この本で一番頂けなかった気がします。
犯人を分かる事が重要ではありませんが、
犯人が分かってしまうとストーリーがある程度頭で組立ってしまうため、
最後まで当たってしまうと内容が半減してしまいます。
この作品で言いたかった事は分かりませんが
まあ、面白いとは言えない作品ですね。

・踊り子
最初から最後まで読むのが辛かった作品です。
引き込まれる事もなく、内容も今一で正直東野圭吾さん好きの私には
がっかりと言っても良い作品です。

・エンドレス・ナイト
踊り子と同じです。
それ以上は書けません。

・白い凶器
読んでいるときは、それなりに引き込まれていたのですが
終わってみると「う~ん」としか言えません。
この辺りが短編って感じです。

・さよならコーチ
正直、あんまり面白くありませんでした。
読み方として間違っているかもしれませんが
犯人が容易に検討が付くので、そこから頭の中で逆に組立ってしまい
証拠等の予想がすべてにおいて的中してしまった作品でした。

・犯人のいない殺人の夜
タイトルになっただけあってこの中では抜群に面白いと思いました。
多分この手の作品にいろいろと読み応えを与えてくれる肉付けがあるだけで
私自身は楽しんで読むのだと思います。
簡潔で良いという考え方もあるとは思いますが、
やっぱりそれなりのボリュームを楽しんでいるところもありますので
短編と言う事が今一でした。

なんか今回はながながと感想を書いてみました。
書いていて思ったのですが、自分が短編を嫌いな訳が分かってきた気がします。

ダメな会社ほど社員をコキ使う

宋 文洲さんの本は初めて読みました。
中身はどこかで読んだ事のある、聞いた事のある内容ですので
特に目新しい事が書いてあったとは思いません。
ただ、タイトルからして何か引きつけるように面白いと思います。
あくまでも伝えている内容は何処かで
一度は耳にしているのではないかと思います。
実践できるかは別にして、実践しようと試みるべき事が書かれています。
私がこの本についてとにかく素晴らしいと思ったのは
すべてを集約したあとがきです。
とりあえず立ち読みで構わないため、一度読んでみるべきです。
そして共感を得たのであれば、手にとってみてはどうかと思います。

水曜日, 5月 14, 2008

将の器 参謀の器

童門冬二さんの本は以前何かを読んだ記憶があるのですが思い出せません。
何かの物事を伝えるのに例を出すのは一般的ですが
この方の歴史を背景にして伝える手法は個人的には面白いです。
歴史が詳しくない私には一石二鳥のような気がします。

この本は言っていたのは
目的を明確にする
動機付けをする
評価を正しく行う
という3点に尽きると思いますが、それを面白く伝えるこの本は
良い本だと思います。

この本は立派なビジネス本ですので間違いがないようにして下さい
レベルのコメントだけ出しておきます

カジノドライブ

先週、アメリカに渡った我が指名馬であるカジノドライブが
ピーターパンSを圧勝しました。
スパークキャンドルも同じレースに出走していたのが少しびっくりです。
これで目標にしているアメリカ3冠の最後であるベルモントSにも
俄然期待が高まります。

POGも今週が終わってしまえば、残すところ1開催となります。
何とかダービーで一花咲かせたいものです。

金曜日, 5月 09, 2008

滑り込みセーフ

先週の土曜日に東京競馬場で青葉賞が行われました。
人気は相当なかったのですが指名馬であるクリスタルウイングが出走しました。
もちろん、本命です。

ただそれよりも重要なのはぼろぼろの本年度のPOGに
ダービー出走という希望の光が差すかどうかが一番の問題でした。

この一番の問題に2着という結果ではありましたが答えてくれました。
これで今年見に行くダービーも面白くなりそうです。
当日は東京競馬場にて勝つことを信じて応援です。

勝ち馬との差は通ったところだと信じてます。
逆転は必ずある!

意識とはなにか―「私」を生成する脳

哲学書みたいな本でしたね。
内容については分かりやすいのですが
正直全体として何を言っていたのか分かっていないような気がします。

ただ、この本は小説ではないため全体で何を言っているという
考え方が間違っているかもしれませんね。

「ふ~ん」と思うところが沢山合ったわけでもないため
何か新しい事を得たのかは相当微妙でした。

それでも最近脳についての話が面白いため
懲りずに次の本を探して読んでみるつもりです。

卒業 -雪月花殺人ゲーム-

中々手に入らなかったので読むのがここまで遅くなってしまいました。
作品としては、読みやすくさくさく読める作品です。
内容が深いかと言えば私の感想はそうではありません。
デビュー作である放課後の方が面白かったです。
この作品のトリックは私には解明することが不可能でした。
知識として持っていないって事なので...
それでも、このトリックで使われたような物質というか材質が
存在するという事実を知っただけでもびっくりでした。

東野圭吾ファンとしては加賀恭一郎の学生時代というところに
感動を少し覚えました。

東野圭吾さんの本を沢山読んだ後では今一です。
早い段階で読むことをお勧めします。

木曜日, 5月 01, 2008

月の扉

面白かったのか?つまらなかったのか?
良く分かりません。
でも、こう思うって事はつまらない部類だと思います。
非現実的な動機は小説なので許せるのですが
何のトリックも感じられない犯行でしたし
ミステリという部類であるかも疑問です。

何より一番疑問なのは(小説とは関係ありませんが)
歌野晶午さんの「葉桜の季節に君を想うということ」とあらそったという事実です。
何処にあらそう要素があったのか私にはまったく分かりませんでした。

ただ、ここまで書いてもAmazon評価は普通にしてしまいました。
これより面白くない本って沢山ありますからね。
特別お勧めはしませんが、暇だったらって感じです。
読み進めやすいですし、途中はどんどん引き込まれる感じはありました。
あくまでも最後まで読んだ時の感想としてはう~んって感じだったという事ですね。

水曜日, 4月 30, 2008

似顔絵

火曜日は住宅公園で似顔絵を書いてくれるという事で遊びに行ってきました。
家の子供の3人の顔はなかなか面白く描けたと思います。
面白いのは帰りの車で長女が3女の絵を下手くそと連呼していた事です。

私と奥さんで次女が一番上手で次が長女、三女はまだ半年という事もあり
絵を見て女の子に見えないところが今一だと言っていたのを聞いたらしく
下手くその連呼でした。

以前から似顔絵を書いて頂きたかったのでとりあえず良かったです。
次はきちっとお金を出して書いてもらおうと思いました。

プールの嵐

ゴールデンウィークの前半が終わりました。
今回は月曜日を休んで4連休、2連発というようにしました。
前半は4日間中、子供の希望もあり3日間もプールに行ってしまいました。
月曜日は長女は幼稚園だったため、初めて次女と二人で行きました。
本当に家の子供はプール好きですね。
ビート板を使って、多少泳ぎますので
本格的に泳げるようになるのも早そうです。

狂骨の夢

京極夏彦さんの3冊目を読破です。
本当にこの作者の作品は面白いですね。
手の平の上で踊らされているところもありますが
内容が面白いので満足です。

このような本の構成にはなれている方なので
読み難い事もなかったのですが
謎が解かれていく過程では驚く事が沢山でした。

最後の部分で登場した顔を頭の中で形成できないという病気については
初めて聞いたのでこれだけでも読んだ価値がありました。

最近、島田荘司さん、京極夏彦さんの本を読んでから
脳医学に興味が沸いてしょうがありません。

水曜日, 4月 23, 2008

進級できたようです

昨日の進級テストは合格したようです。
ただ、そこまで喜んではいなかったようです。

それでも帰宅すると、「進級したんだよ」と一言発してくれました。

ハッピーバースディの方を非常に喜んでくれたので
(と言ってもケーキが食べられるという事だけですが...)
それは良かったです。

面白かったのは、次女が「誕生日おめでとう」と書いてある
プレートを食べようとしたところですね。

火曜日, 4月 22, 2008

今日は4歳の誕生日です

今日は、長女が4歳になりました。
考えてみれば、この子が生まれてから人生はがらっと変わった気がします。
結婚、転職など様々な出来事はありましたが
長女誕生に勝る出来事はありませんでした。

その後、次女、3女と生まれましたが長女誕生に勝る人生の変化は
なかったように思います。
そういった意味では、特別な子供なのでしょうね。

もちろん、次女、3女より好きだとか言った意味ではありませんが
子供は子供で同じようにみんな好きです。
ただ、人生に一番影響を与えてくれたのは長女という意味ですね。

もう、幼稚園にも通い、順調に育ってくれています。
今日、プールで進級テストがあるようです。
バースディプレゼントで進級できると良いのですがね。
まあ、本人が望んでいるかは分かりませんが。

おしかった皐月賞

皐月賞の馬券で何が難しかったのかは分かりませんが
個人的な予想としては物凄くおしかったと思ってます。
逃げ馬が、逃げきる展開と予想をして
大外というところに一抹の不安はあったですが
本命にしたのはショウナナルバ。

しかし、残念ながら前に行くことはせずに押さえてしまいました。
スプリングSでかかって、最後に差された事を反省しての競馬でしょうが
正直、がっかりです。

それに対して、個人的に理想的な競馬をしたのが
勝ち馬であるキャプテントゥーレですね。
この馬が逃げる事は残念ながら予想外だったため
まったく購入しませんでした。

2着、3着はがっつり入っていましたし、
人気馬でも、ブラックシェルは1円も購入せずなど、
この辺りは良かったのですがね。

連敗街道はまだまだ続きます。

木曜日, 4月 17, 2008

論理哲学論考

とりあえず読み切りましたが、私には非常に難しい本でした。
ただ何点か良く分かった箇所もあり分からない事が多いのですが
面白かったです。
今は2度目を読むか、この本の補助本を読むかを検討中です。
とにかく、脳みそフル回転で理解に努めようとしても
難しい内容だったのは間違いありません。
でも、何点か理解できた箇所はそれはそれで
いろいろと考えさせれれるところもあり面白かったですね。

次はとりあえず、推理小説を読んで少し休憩です。

火曜日, 4月 15, 2008

本質安全と機能安全

少し面白い話を見つけたので触れてみたいと思います。
今回のタイトルである「本質安全」と「機能安全」という言葉です。

「本質安全」とは危害を及ぼす原因そのものを除去してしまう
「機能安全」とは極力安全を確保するという概念
だそうです。

どう考えても本質安全の方がよいのですが
これで対応できるものは対応すれば良いのですが
できないものが非常に多くあり、
それらについての対応を機能安全で考える事になるのでしょう。

私が見た資料では
「踏切事故対策なら立体交差化で踏切をなくしてしまうこと」
という本質安全の対策が出ていました。
なるほどと思いますが、これは現実的ではないというのが問題です。

交通事故を完全になくそうと思ったら人間が歩く箇所と
自動車が走る箇所を完全に分離してしまえば良いという事です。
しかし、自動車に乗り降りをする以上、必ず重なる箇所が出てきますし
それ以上に、完全分離というのは無理があります。
今現在行われている、車道、歩道というものが機能安全というものでしょう。
歩道が完全に確保されている場所であればあるほど
事故は少ないのではないでしょうかね。

私の仕事はシステム開発ですので、この問題を私の仕事に置き換えてみれば
本質改善の究極は「故障のないソフトウェア」という事になるのでしょう。
これに近づけるためにテスト工程に、「リソース」、「時間」を投入しますが
実際問題、故障がないソフトというものありません。
私のシステムは故障がないという人もいるかもしれませんが
おそらく発生していないのだと思います。(もちろんシステム規模によりますが)

様々のフレームワークを駆使し、標準化手法で過去の経験を生かし
同じ失敗を繰り返さないという努力はどこも行っていると思います。
この考え方が「機能安全」という事になるのでしょう。

「本質安全 機能安全」でググってみるとパワーポイントの
ファイルが見つかりますので興味があれば読んでみて下さい

日曜日, 4月 13, 2008

数学と論理をめぐる不思議な冒険

現在、同時にいろいろな本を読書中でなかなか1冊が終わりません。
時間がかかってしまいましたが、この本が一番に読み終わりました。
ずばり数学の本です。
まったく別の内容の本を想像していたので、
正直期待外れなところはありました。
ただ、それは私個人の話ですから
この本について客観的に評価をするのであれば
読み物としては以外と面白いと思います。

たぶん、人によっては「へぇ~」って内容が出てきます。
それだけでも面白いのではないかと思います。
数学を知っている必要はないです。
また、頭から読む必要もないと思います。
タイトルから分かりやすそうな章を読めば良いと思います。
そういう意味では自由な本ですね。

ありえません

本日の桜花賞。何やってんだかって感じです。
ちなみに、私の本命はリトルアマポーラ。
対抗にエイムアットビップ、ソーマジック、ブラックエンブレムの3頭。
トールポピーはどうも強く思えないため遠慮。
オディールは信用できないため、こちらも遠慮です。

レースが始まると、エイムアットビップは逃げる理想的な展開です。
この段階でエイムアットビップが飛んでも諦めが付く状態でした。
とにかく、この馬は逃げてこそと思っていたので
最近の2戦は私の中では度外視。
しかし、強いと思っていたので買い続けてきましたが
今回は力負けという事にしておきます。
本当は武豊で見てみたいのが本音ですが…

エイムアトビップが逃げ切るのではないかと思えた4コーナー。
リトルアマポーラがいないじゃないですか!
大外を回ってきています。
一番の心配事であった武幸四郎君が炸裂したと思った瞬間です。
それでも馬の能力が違うと信じてはいましたが
一緒に伸びてきたトールポピーは振り切ったものの
まったくと言ってよいほどの届かずでした。

レースは大荒れでしたね。
突き抜けたように見えた勝ち馬よりも良い脚を使ったのがリトルアマポーラです。
オークスは突き抜ける本命になりそうな予感があります。
それにしてもがっかりです。どうして強い馬が勝たないのでしょうかね。
今年の3歳は本当に難しいです。
勝った馬は強いです。
でも一番強くないよな!って思ってしまうのが今年の3歳です。

木曜日, 4月 10, 2008

入園式

昨日は長女の入園式でした。
4月生まれのせいか、大きい方でしたね。
近所の子供で仲が良い友達がいたようで
仲良く遊んでいた光景はちょっとした感動でしたね。
次女は3月生まれで来年入園となるのですが
今の段階でも臆する事なく一緒に遊ぼうとしている姿を見ると
来年は今年よりは苦労するのかなって思っていましたが
大した問題はなさそうですね。

次女にしてみると遊び友達の長女がいなくなる事が
今後の生活にどのように影響するのかが非常に楽しみです。

日曜日, 4月 06, 2008

明日は初戦

明日は産経大阪杯です。
今年のダイワスカーレットの初戦になります。
1番人気はてっきりメイショウサムソンと思い切っていたのですが
どうもダイワに収まりそうですね。

そうなってくると、馬券の検討が一捻り必要になってきます。
馬単1点で7,8倍は期待していたのですが5倍台になりそうですね。
馬券の検討が3連単まで必要になってしまいました。

こんな事してしまうから外れちゃんですよね。

ユーザーとの関係

システム開発を行う上で絶対に必要な人は間違いなくユーザーです。
システムから見れば開発ベンダーは何処でも良いですが、
要件定義元であるユーザーは変更する事はできません。
変更するという事はシステムが変わるという事になりますので...

で開発ベンダーとユーザーの関係を考えます。
開発ベンダーはユーザーから仕事を頂いて働くわけですから
ユーザーは開発ベンダーから見ればお客という事になります。

「お客様は神様である」という話が良く聞かれますが私の考え方は違います。
ユーザーが開発ベンダーを決定した段階で関係は対等です。
後は一つの目標に向かって協力していく必要があります。

開発ベンダーは手を抜いて儲けようとは思ってはいけませんし
ユーザーは抽象化させ過ぎて何でもかんでも
開発ベンダーに作業させてはいけません。

直接的な事を言えば
「一定の作業を一定期間で完了させる事をある金額」で受注しています。
それを超えた場合、契約範囲外作業となり契約上お客ではなくなります。
もちろん、こんなにドライな意見が現場で通る訳ではありませんが
これは常に頭で考えて置くべきです。

つまり作業を行う時は、範囲外作業となってしまう場合
過剰な機能を作成しようとしている可能性があります。
それを開発ベンダーはコントロールする必要があります。
時には「それは契約外機能となるので追加が発生する」と
言って上げる事が良い事もあるでしょう。

逆にユーザーは要件を決める上で欲張ってはいけないという事になります。
自分達は何を作りたいのかを常に考えて要件を決める必要があります。
これがぶれると過剰な機能が原因で、本当に必要な機能を影響を与える。
パフォーマンスを期待しているのに過剰な要件のために大幅に劣化してしまう
と言う事になります。
ユーザーが一番考える必要があるのは
「システムを作るのは自分達である」という自覚でしょう。

それぞれこのような立場で仕事をする人が
上手に付き合っていくには信頼関係が必要になります。
これを築く事ができれば、お互いに本当の目標を共有できる事になるので
それを達成するための最も良い方法を考える事になります。

またお互いには、それぞれの仕事があるという事も重要であると考えます。
そのため余計な口出しは不要という事です。

開発ベンダーは過剰に発生してしまう要件から
本当に実現したい要件は何であるのか見極め、
ユーザーに理解させる事から始める必要があります。
それは、要件を変えるという事ではなく気付かせるという事です。
そして決まった要件を開発ベンダーの勝手な要望で変更する事はできません。
あくまでも要件を決めるはユーザーです。

またユーザーは開発ベンダーが要件を実現する方法に対して
議論するドキュメントが存在し、
それについてはお互いに議論をすれば良いのですが
その先に開発ベンダーが作成するドキュメントに対しては
口を挟んではいけないと考えます。
ユーザーが読むという事は開発ベンダーは
ユーザーが理解できるように作成する必要が出てきます。
必ずしもそれは良いドキュメントとは言えないからです。
通常は悪くなると考えるべきです。


必ずお互いの立場を尊重して仕事をする必要がありますね。
どちらかが偉いという事もなければ、
どちらかが不必要という事もありませんので。

木曜日, 4月 03, 2008

ユーザーインターフェースの基本

突然ですが今回は上流設計で行われるユーザーインターフェース設計
における基本的な考え方を一つ書いてみます。
非常に重要な考え方ですので、意識していなかった人がいれば
意識をして欲しいですし、無意識で行っていたのであれば
今一度概念として理解をして今までの事を確かめてもらえればと思います。

「fool proof」
・「馬鹿な事をしても大丈夫」

「affordance」
・「提供する」

直訳するとこんな感じでしょうか?


最初の「fool proof」は以下のような考え方です。
ユーザーとはミスをするものです。
それで製品、システムを壊してしまっては
ミスをした人が悪いとは言えません。
ミスをしたって大丈夫な仕掛けが必要です。
理解としてはこんなところですね。

これを前提に物事を考えると
良いユーザーインターフェースとは
ミスをしないユーザーインターフェースという事になります。

良いと思うインターフェースは
・オートマミッションでパーキングからギアチェンジする時はボタンを押下しなければならない
→子供が間違って当たってしまってもギアが変わる心配はない

・ドアを閉めないと開始できない電子レンジ
→間違って加熱しようがない

ダメなインターフェースは
・突然電源を切ると、壊れる可能性のあるパソコン
※辞めたくなったら電源を切るというのが人間の心理です。正常に終了させなかったから故障している可能性がある
→電源を切ったら、自動的に正常終了させる手順が動いてくれれば良い

・購入したい切符を選択する前に金額を入れられる券売機
※金額購入後に、間違った金額を押してしまうと、お金が過不足なければ購入できてしまう
→お金が入れられなければこんな事は発生しない。

などが個人的には該当します。


次に「affordance」は以下のような考え方です。
ボタンがあれば押してみるし、取っ手があれば引いてみる。
つまり人間の心理としてそうしたくなるユーザーインターフェースを
選択するという意味です。
これは、様々な分野のユーザーインターフェースを研究し
同じような方法を選択する事で
いろいろな機会に自然と教育が行われているのではないでしょうか?

例えば、ノブ付きのドアがあり押しても引いてもドアが開きません。
これが引き戸だった場合、どう思うでしょう。
何でこんなノブを付けたんだって思いますね。
お笑い番組のコントでありそうな話です。
何でこれはコントになるかと言えば、
多くの人はドアを見ると、押すか引くかしてドアを開けると想像するからですね。
つまり、このようなドアの場合「押す」又は「引く」というのが自然な行動です。
このようなインターフェースを選択すれば間違いが少ないという事になります。

「住所を入力して下さい」とだけ画面に書かれていて
入力できる箇所が沢山あったら、入力する人はどう思うでしょうか?
「何処に何を入力すれば良いの?」って事になります。

一つ一つの入力箇所の左、上などに
「都道府県」「市区町村」と書いて上げれば
それだけで間違いは大幅に減ります。
これが「affordance」という考え方を考慮した
ユーザーインターフェースです。

エレベーターなどが良いインターフェースの見本ではないでしょうか?

新歓

昨日は4/1で新歓があって参加してきました。
新人さんとは話はできませんでしたが、
フリーの私としては、このような機会を与えてくれた会社には
本当に感謝です。
会社の人間で、あのような場所会う人は大体知り合いなのですが
それでも知らない人がいたり、最近入った人がいたりで
本当に面白い会でした。

さすがにこの時期は飲む機会が多いので財布がキツイデスネ。
って言っても新歓には一銭も払っていませんが...

日曜日, 3月 30, 2008

ショック

あんなに負けると思いませんでした。
一番ショックはヴァーミリアンですね。
日本で圧倒的な強さでダートを勝ったにも関わらず
まったく通用しませんでした。
正直、こんな結末があるとはまったく思っていませんでした。

デューティーフリーは相手が強いと読んでいたので
どんな感じなのか興味がありましたが
正直、アドマイヤオーラとウォッカの差は騎手の差である気がしてます。
安藤勝さんが悪いというよりはさすがにドバイでの経験は武豊が上かと思います。

それ以上に強烈だったのはウォッカの競馬です。
あんなに前につけれるんじゃんってのが感想。
正直、四位さんとの腕の差を見ましたね。
最後方しか付けれないと読んだ気がしますが
あの位置につけれるんじゃん。

水曜日, 3月 26, 2008

ステップファザー・ステップ

宮部みゆきさんの短編小説です。
ただ、短編と言っても帯ドラマみたいな構成になっていますので
純粋な短編ではありません。
これは何かの連載だったのでしょう。

内容は面白い部類に入ります。
なぜこんな言い方かと言えば、宮部みゆきさんの作品は面白いのが多いからです。
最初に読む本として薦めません。

もし、宮部みゆきさんの本を何冊も読んでいて
次に何を読もうか探している人がいればお薦めです。

泥棒と子供の暖かい話でミステリーとは言えないです。
物語という部類になると思います。
題材として斬新ですのでドラマにしても良いかもしれません。

日曜日, 3月 23, 2008

FONのルーターが到着

FONのルーターである「LA FONERA+」がやっと来ました。
家の無線LANをLA FONERA+に変更し、
IPOD TOUCHでFON_APの方に接続して確認OKです。

初めてIPOD TOUCHでインターネットを行いましたが
これが以外に良いような悪いような感じです。
マウスクリックのみで行うようなインターネット使用はまったく問題なく、
画面が小さい事もIPOD TOUCH特有のインターフェースが
まったくそれをストレスに感じさせません。

が、文字入力についてははっきり言って駄目です。
このインターフェースは非常に頂けません。
考えてみると、タッチペンがないのも頂けませんね。
まあ、これはメインのターミナルとして購入していないのが救いですね。

まあ、もともと無線がa規格だったためWiFiが使用できなかったのですが
FONルーターに変更した事で、その辺は解消されました。
良く考えてみると、家に無線LANを構築する際に、
購入したのに2万近くしたのですが、FONのルーターは5000円程度です。
安くなったものです。

みなさんもFONに参加して、もっともっと使い勝手の良いものにしましょう

今からF1

今からF1マレーシアグランプリのTV観戦です。
初戦はフェラーリぼろぼろだったので、
2戦目は期待です。
ポールがマッサ、2番手がライコネンと
フロントロー独占ですから、今回は期待です。
非常に楽しみです。

さすがに諦めがついた

今日阪神2Rでアドマイヤアタックがまたまた惨敗しました。
強い強いと思って4戦目。
さすがに諦めが付きました。

友人指名馬のノットアローンの若葉S逃げ切りにより
状況も非常に悪くなってしまいました。
本番どうのこうのの心配はしていないですが...

よく考えてみると、POGをはじめてからの
初めての皐月賞出走が叶いませんでした。
これもさびしい事実ですね。

今は、プリンシパルSにクリスタルウィングが
勝ってくれる事を祈るのみです。

火曜日, 3月 18, 2008

ユニットテスト

ユニットテスト(単体テスト)はホワイトボックステスト、ブラックボックステストの
2つのテストを実施する事で完了とする事が一般的である。
この2つのテストについて自分なりに考えてみる。

ホワイトボックステストとはプログラムの処理方式をテストする手法で
ソースコードからテストケースを作成する必要がある。

もちろん、このテスト方法を否定する事をするわけではない。
これは歴史的発展を遂げてきたテスト手法であり間違っているわけではない。

ただ、最近のプロジェクトはこのホワイトボックステストをじっくり行う
テスト期間がないような気がしている。
もちろん、昔に比べるとデバッガなどのツールが整備されており
実施そのものは行いやすくなって事は否定しない。

ホワイトボックステストとして定義されるテストには
以下のようなテストが存在する。

・カバレッジテスト
プログラムの全ての行をトレースするというテストである

カバレッジテストはホワイトボックステストの中でも
一番重要なテストだと考えている。
しかし、便利過ぎるデバッガがカバレッジテストの重要性を
見えなくしている気もしている。
カバレッジテストとは本来テストデータによって
カバレッジを上げる事が目的であるが
それをせずに同一データでデバッガのブレイクポイントと変数代入を
使用して無理やり分岐を通すテストを実施する人が多いという問題である。
もちろん、担当者のスキル問題ではあるのだが
そもそもツールが存在しなければこんな事にはならなかったのも事実である。

何で、こんな事が起きるかと言えばカバレッジテストという内容を
理解していないのが原因だと考えている。

この対策として私が考える一番単純な方法は異常系テストを除いて、
デバッガの変数代入機能の使用禁止である。

また、カバレッジでは網羅していないデータが存在するのも事実である。
それは文1、文2のIF文が存在すれば全部で組み合わせは4種類存在する。
しかし、カバレッジという観点で言えば「true-true」「false-false」で
完了してしまう。
このような事がおきないようにデシジョンテーブルを作成して
カバレッジを上げる必要性がある。

つまり私が考えるカバレッジテストとは、
「デシジョンテーブルの作成」→「全てのデータを走行」→「未テスト部分の検証」
結果がデシジョンテーブルの抜けではなく異常系と判断されれば
デバッガを利用しての未テスト部分の走行、検証。
デシジョンテーブルの抜けと判断された場合は
最初に戻ってやり直しという方法である。


・境界値テスト
プログラムの中を理解している人間はループの終了条件や
分岐文の境界を理解している。
これに特化したテストケースを実施する事である。

このテストで一番重要なのは、分岐文やループ終了条件に記述される
境界値が「なぜこの数値なのか?」という事を考えることである。
実際問題、境界値テストケースを作成する事で
その分岐文を参照する事になるため
テストケースを作成した時にテスト結果がどうなるか容易に想像する事ができる。

であれば問題なのは、そもそも「その分岐文はあっているのか?」
「その終了条件は合っているのか?」という事を考えることである。

これで境界値テストは終わったようなものである。
もし、テスト担当者がその理由を答えられない場合
テストケースをパスする事ができても、テストケースが間違っている事を
検出する事はできない。
つまり、分からなかった段階で設計者又は分かる人間に聞く必要がある
という事になる。

・アルゴリズムテスト
これは単純にアルゴリズムを検証するテストである。
「静的検証」と「動的検証」の2種類を行う必要がある。

「静的検証」とはプログラムソースレビューを指し
「アルゴリズムが性能的に問題がないか?」
「分かりやすいアルゴリズムになっているか?」
と言った観点でレビューを行う。

「動的検証」とはアルゴリズムが期待している結果を出すかという検証であり、
いわゆるテストと言われるものである。

これで一番重要だと考えるのは「静的検証」を実施する事である。
これは意外と実施されない傾向にあるがとても重要な事である。


ブラックボックステストとは、インデータに対して期待するアウトデータを定義し
その結果のみを確認するテストである。
アウトデータが正しい内容であれば、
その生成方法については問わないという考え方である。

ホワイトボックステストを実施した前提であれば
ブラックボックステストで行う必要があるのはそんなに存在しない。
カバレッジテストの箇所で触れたデシジョンテーブルが
きちっとテストされる事で基本的には
そのプログラムファイルに期待するテストを実施している事になるからである。

つまり私自身はユニットテストにブラックボックステストは
必要ないと考えている人間である。
正確なホワイトボックステストを実施すれば十分である。

月曜日, 3月 17, 2008

クリスタルウイング

やっと2勝馬の誕生です。
時期が少し遅かったため皐月賞にま間に合いませんでしたが
藤沢厩舎であること、ゼンノロブロイ、シンボリクリスエスの例もありますので
まだまだ諦める必要がないシーズンとなりました。
他は全てダート馬のような感じですので、私の今シーズンは実質この馬1頭です。

時計、上がりを考えるとレースそのものは以外と不満がある内容だったのですが
勝ったという事のみを評価したいですね。
実は、エンジンが2段、3段隠されているという事に期待です。

次走はダービートライアルという事なのでプリんシパルSか青葉賞となるようです。
他にもレッドシューターという馬が同厩舎にいますから
その馬との兼ね合いになるのでしょう。

どちらにしても、この馬たよりですから期待です。

ハミルトン

開幕戦はあいかわらずのサバイバル戦でした。
その中でも諦めずに地道に走った中島一貴の6位はすばらしいですね。
クサビとの接触で次は10番グリッド降格らしいですが
そんな事は気にせずにがんばってほしいですね。
チームメイトが表彰台をとった事を考えると
マシンポテンシャルは以外と高いかもしれませんね。
今シーズンで表彰台を上る事を目指してほしいですね。

レースそのものはハミルトンが勝利しました。
それについては正直つまらない結果となりました。
マクラーレンのマシンは相変わらず速いようですね。
フェラーリは単純に自滅にしか思えません。
ライコネンは完全に不付きでしたね。

次こそ速いフェラーリを見せてほしいです。

土曜日, 3月 15, 2008

2008シーズン開幕

2008シーズンが始まりました。
ポールはハミルトンで、ライコネン、アロンソと大分後ろになりました。
チームの勢力は認識していいないのですが、
昨年優勝を争った3人ドライバー対決になれば、
3チームの対決なので少し面白いかもしれませんね。

日本人は後ろですが、中島のチームメイトが7番手にいる事を考えると
中島マシンのポテンシャルはありそうですね。

本番タイプかもしれませんので楽しみです。
スーパーアグリはマシンが苦しい状況かもしれませんね。

佐藤琢磨にはがんばってほしいですが、
如何せんマシンの不利はどうしようもなさそうです。

C++解説17(デフォルト引数)

C++にはデフォルトパラメータという機能があります。
これは引数が与えられなかった場合、
デフォルト定義したパラメータが与えられたとして動く機能です。
また引数として省略できるのは後半のパラメータです。

Add(int &lhs, int rhs = 1);

この関数Addはlhsにrhsの値を加算する単純な関数ですが
もしrhsである第2引数を省略した場合
1を加算する関数になります。

int main(void) {
int i = j = 2;

Add(i, j); // 2+2
Add(i); // 4+1
}

1回目のAddは引数の省略がないため
そのまま値が使われ「2+2」となり
2回目のAddは第2引数省略となっているため
第2引数にはデフォルト引数である「1」が使用される。

Add(int &lhs, int rhs = 1);
Add(int &lhs, int rhs = 2);
もちろん、これはエラーである。
Addを使用した時にどちらを呼び出せば良いか
分からなくなるからです。

今回はちょっとした事ですが、意外と重宝できる機能ですので
照会してみました。

木曜日, 3月 13, 2008

スナーク狩り

この本はもの凄く面白かったです。
本格推理というよりは、サスペンスの物語です。
トリックがどうとかいう本ではなく、
それぞれの物語(ここでいう物語とは、登場人物一人一人の話です)が
一つに繋がっていき、最後には考えさせられる話でした。

上手く表現できませんが、話にはスピード感がありました。
展開が速く、あっという間に話が次々と進んで行きます。
いくつかの物語を繋げるところは絶妙で、とにかく面白い本でした。

宮部みゆきさんの本は面白い本が多いですが
この本もその中でお勧めの本であることは間違いありません。

味気ないかもしれませんが、宮部みゆきさんの本を読んでいるだけでも
いろいろな話に出会うことができます。

火曜日, 3月 11, 2008

脳を活かす勉強法

茂木さんの本ですね。
ベストセラーみたいです。
内容的にはどこかで読んだ事がある自己啓発書みたいな内容です。
もちろん、茂木さんが書いているので脳に対してという解説が
たくさん登場し、その部分は最高に面白いです。
でも、これは個人の感じ方でしょうね。
私自身は脳というものに非常に興味があるため
「脳の中でどのように解釈されるか?」とか「脳の中で何が起こっているか?」
などが解説されている本は大好きです。
推理小説でも脳を扱った内容は、それだけで面白いと感じてしまうほどです。

私は非常にお勧めします。
いくつか共感を覚えた題をあげておきます。
興味があれば、立ち読みでも良いと思いますので目を通してみて下さい。
ただ、こういった本は何回も読むものだと思いますので購入がお勧めです。

1.「喜び」がないと強化回路が回らない
2.一つひとつの行動に負荷をかける
3.「成果を他人と比較する」なんて、デメリットだらけ
4.細切れ時間こそ、できることが無限になる
5.少し難しい内容の本を読むことが、脳に快楽を与える

読み易い本ですし、本当にお勧めします。

C++解説16(Exception2)

例外処理について考えた場合、string型やint型では多くのケースが
情報不足に陥る事になる。
そこで例外クラスを作成する事が一般的だと思います。

もの凄く汎用的なクラスを作成してしまえば

class base_error {
private:
int nRetCode, nDtlCode;
public:
base_error () { nRetCode = 0; nDtlCode = 0; }
base_error (int InRetCode, int InDtlCode) { nRetCode = InRetCode; nDtlCode = InDtlCode; }
void Print_ErrMsg() const {
cerr << "Error RET[" << nRetCode << "] DTL[" << nDtlCode << "]\n";
}
};

これは何の情報もないエラークラスです。
これを派生させて、様々なエラークラスを作成してしまえば良いのです。
なので全てのエラーの既定クラスとするbase_errorの「Print_ErrMsg」は
virtual宣言に変えておきましょう。

では派生させてみましょう。
「数値型」を受けるクラスのメソッドについて考えてみます。
このメソッドが引数に期待している値が「0~99」だとします。
その場合、引数に対して「0 <= 引数 <= 99」といったチェックが行われるでしょう。
そして、この条件が満たされなかった場合「Out Of Range」という事なり例外発生です。
このような場合、エラー情報として実際に何が引数に渡されたのかを出力するのが通常です。

class OutOfRange : public base_error {
private:
string strFuncName;
int nValue;
public:
OutOfRange (string InFuncName, int InValue) { strFuncName = InFuncName; nValue = InValue; }
void Print_ErrMsg() const {
cerr << strFuncName << "::OutOfRange value = [" << InValue << "]n";
}
};

これで完成です。
後はこれを捕捉すれば良い事になります。
ここでちょっとした工夫が必要になります。

単純に書けば

try {
func();
} catch (OutOfRange o) {
o.Print_ErrMsg();
}

とすれば良いのですが、もちろんこれは違います。
絶対的に違うのは、何のためにbase_errorを派生させたかって事です。
「OutOfRange」というクラスオブジェクトの時のみ特殊な動きが発生する場合
この方法もありますが、上は単純にエラーメッセージを出力しているのみです。
であれば、基底クラスである「base_error」で捕捉をするのが通常の方法です。

try {
func();
} catch (base_error o) {
o.Print_ErrMsg();
}

となります。
実は、これでも不十分となります。
何故なら、「base_error o」というように値で捕捉をしているからです。
値で捕捉しているという事は「o.Print_ErrMsg()」で出力されるのは
基底クラスの「Print_ErrMsg()」という事になりますね。
そのため、アドレスという形(参照で問題ありません)で捕捉をする必要があります。

try {
func();
} catch (base_error &o) {
o.Print_ErrMsg();
}

が期待している形になります。
後は、様々な例外クラスを派生クラスという形で作成していく事で
ある規則に従って記述されたメイン処理は余す事なく例外を捕捉出来る事になります。

月曜日, 3月 10, 2008

C++解説15(Exception1)

プログラムが異常した場合の処理をどのように記述してきたか?
C++以前の言語とC++以降の言語では
この辺りが大きく違うのではないでしょうか?

まあ、今回説明するExceptionと言うものの
元祖がC++なのか良く分かっていないのですが
私自身はC++で始めて出合った構文です。


この機能の素晴らしさはC言語プログラマであれば
絶対に分かる機能だと思います。

プログラムが異常した場合、終了させる方法は2つあります。
1つ目は「abort()」という手段で終わらせる方法
2つ目は「main」を正常復帰値以外で終わらせる方法です。

1つ目の方法は全てを破棄する方法ですから
特別な制御は不要です。

どのようなプログラムを作成するかによりますが
私自身はあんまり行わない終了方法です。
まあ私自身はオンラインプログラムが多く
しかもクラッシュさせる事が
絶対にできないシステム開発ばかりであったため
「abort()」という選択肢はありませんでした。

そのため必然的に2つ目の方法である
「main」の異常復帰という方法を取りました。
もちろん、データ不正などデータベース等にログしているデータが
不正の場合、続行は不可能です。
こういった場合、その影響範囲を最小にするための
制御としてクラッシュさせるわけにいかなかったと言う事です。

少し勉強した時はC言語の標準関数は「errono」に値を返す事を
利用してプログラムを組んだ時期もありましたが(こっちは趣味です)
基本的にはライブラリを使う人間としては
なぜライブラリの使用ができなかったのかというエラーは
あんまり重要ではない事がほとんどでした。

要するに、失敗したという事実が確認できれば十分であると言う事です。
そうなってくると「errono」の使用は少しづつ行う事をしなくなりました。

すると関数を呼び出し、その復帰値を参照し問題なければ次に。
また別の関数を呼び出し、また復帰値を参照し問題なければ次に。
という方法でプログラムを書く事が普通となります。

これは当り前なのですが、実はC言語では諦めている境地で
C++ではこんな方法はありえないと言う事になります。

例として制御関数「ctl_main()」が「int funcA()」「int funcB()」「int funcC()」
を呼び出ししているプログラムというものは
基本的には以下の通りになります。

int ctl_main() {
int nRet;

nRet = funcA();
if (nRet != 0) {
return nRet;
}

nRet = funcB();
if (nRet != 0) {
return nRet;
}

nRet = funcC();
if (nRet != 0) {
return nRet;
}

return nRet;
}

これは当たり前のようで物凄く読み辛いプログラムです。
異常系のロジックが半分以上埋め込まれている事がその原因です。

これをC++では以下の通りで表現する事ができます。

「void funcA() throw(string)」
「void funcB() throw(string)」
「void funcC() throw(string)」

int ctl_main() {
try {
funcA();
funcB();
funcC();
} catch(string e) {
cout << e << endl;
return -1;
}

return 0;
}

これは「funcA」「funcB」「funcC」が異常発生の時に
例外を「throw(発生させる)」するので、
異常系処理を行う必要がある場合に、
その例外を「catch(例外処理を行う事を宣言)」して
処理を行う。

例えば、あんまり良い例ではないが1例示します。
「funcA」「funcB」「funcC」が「引数:char」を取り、
以下の事をcheckする関数とします。
funcA:数字であるか判定
funcB:偶数であるか判定
funcC:3の倍数であるか判定

上記の3関数はCheck結果がNGとなる場合、例外を発生させます。

void funcA(char c) throw(string) {
if(('0' <= c) && (c <= '9')) {
} else {
throw string("Param is not Numeric.");
}
}

void funcB(char c) throw(string) {
if (c % 2) {
throw string("Param is not even.");
}
}

void funcB(char c) throw(string) {
if (c % 3) {
throw string("Param is not multiple of three.");
}
}

int ctl_main() {
try {
funcA();
funcB();
funcC();
} catch(string e) {
cout << e << endl;
return -1;
}

return 0;
}

これはthrowされた内容が出力されて異常終了する事になります。
この記述の優れているところは、
正常系処理の中に異常系処理を書く必要がなく
非常にプログラムが見やすいというところです。

次回は具体的な使い方を見ていきます。

土曜日, 3月 08, 2008

エデンの命題

「エデンの命題」は個人的には面白かったです。
ただ世間的には良く分かりませんが...
島田荘司さんの作品の中では、かなり読み易い部類ではないかと思います。
斬新なトリックがあるわけではないのですが
たんたんと進むストーリでも、アダムとイブという題材が個人的に
良かったのか、とっても面白かったです。

この本は2作あるのですが、2作目の「へルター・スケルター」
という作品もなかなか良かったです。
この作品は何と言っても脳を扱っているところが私が共感したところでしょうね。
最近、脳の話を読むのが好きなので
この手の話に触れるだけで、何となくすばらしいものだと思ってしまうのは
現在の私の病気かもしれません。
ストーリがもの凄く面白いわけでもないため
何で、こんなにこの本に共感を覚えているのかは良く分かりません。

それでも私がこの本が大好きです。

火曜日, 3月 04, 2008

次女が2歳になりました

本日、次女の2歳の誕生日です。
ここまで順調に育ってくれたのはなによりです。
去年は以外と身近なところで、子供に大変な事が続いていたので
無事に生まれた家の3女や、順調に育ってくれている長女、次女は
それだけで、本当に親孝行なのだと感じた昨年でしたね。

家の次女は長女に比べるといろいろと早い段階で覚えています。
長女の存在が全てなのでしょうが、
それでも凄いと感じさせるところはたくさんあります。

発する言葉も順調に増えていて最近は満足な会話も行えています。
自己主張もなかなか行っています。
一番可愛い時期と言われる3歳前の1年です。
まだまだ楽しみをプレゼントしてくれそうです。

日曜日, 3月 02, 2008

予想が当たらない。

最近、競馬予想は完全に氷河期に突入した気がします。
とにかく当りません。というか馬券が上手く買えていません。

今回の中山記念は逃げるコウゴウリキシオーをエアシェイディが差しきるとの
つまらない予想であったため結果はどうでも良いのですが...
(まったく当たらなかったため、しょうがないという意味です)

阪急杯は完全にミスです。
予想はスズカフェニックスが飛んでくるが
開幕週である阪神の馬場は前がとまらずローレルゲレイロが逃げ切る予想です。
はっきり言って完璧な予想でした。
3連単とは言いませんが、馬単が1点であたっていた予想です。
それを直接馬券に結びつける事ができずに外れました。
オッズを見て、つまらないのでもう一ひねりしてしまいました。
オースミダイドウがローレルゲレイロを抑えて逃げ切るという予想です。
まったく無駄な予想です。
今から考えれば、20倍ちかくも付くオッズが不満か!って話です。
まったく情けないですね。

来週はチューリップ賞と弥生賞という3歳戦ですから
はっきり言って非常に予想が難しいですね。
特に今年の3歳は何が強いのかさっぱり分かりません。
もしかしたら、ダービーを勝利する馬は
未だにデビューしていないのではないか?
とすら思ってしまします。

兎に角、初心に戻り、馬連予想でしっかり当てて行きたいですね。

上昇傾向

本日も指名馬の1頭であるクリスタルウィングが勝利を収め2週連続の勝利です。
両方とも藤沢和厩舎から指名した馬で連続の勝利は気分が良いですね。
まあ、新馬戦、未勝利戦ですから獲得賞金はたいした事がないのですが
気持ちが全然違います。

先週のカジノドライブは海外が決まっていますし
なかなか成績が残せませんでしたが
ドラフト1位のスパークキャンドルは帯同馬として一緒に渡米するようです。

そうすると、今日勝利したクリスタルウィングに過度な期待を寄せてしまうのですが
今日のレースでは、上がりが速いのは良いのですが
基本的にエンジンがかかるのがどうも遅い気がしてしょうがありません。
また、3コーナーから4コーナーにかけて、追走できていなかった気がします。
直線向いてしまえば、圧倒的な追い込みでしたが
これでは重賞クラスはちょっと難しいかもしれませんね。
まあ、それでもこの馬に期待するしかないのですけどね。

パーフェクト・ブルー

犬が主人公と言っても良い作品のパーフェクト・ブルーです。
宮部みゆきさんの作品で、作品名は忘れましたが
これの続編に当たる作品を最初に読んだ記憶があります。
続編よか面白かったような気がします。

このシリーズは犯人が横溝正史的なところがあり
前回も含めて意外な人が犯人だったような気がします。

小説の視点が人間ではない作品って面白いんですよね。
そんな作品を読んだ事がない人は読んでみるのもよいと思いますね。

宮部みゆきさんの作品は基本的に外れません。

火曜日, 2月 26, 2008

地頭力を鍛える

ひさしぶりの自己啓発書でしたね。
内容は非常に面白いもので何回も読む必要がある本ですね。
むかし読んだロジカルシンキングの内容もかなり登場し数学的思考である
「問題の抽象化」→「抽象化問題解決」→「定理化」→「具体的問題解決」
というシーケンスも登場していましたね。

具体的に書けばこの本は
フェルミ推定と言われる有名な考え方について解説した本です。
フェミル推定がどんな考え方であるかは本を読めば分かるので
その内容は伏せますが、この本を読むと一つの考え方を知ることができます。
この考え方を応用できるかどうかは今後の自分次第ですが
それでも自分の考え方を広げるきっかけ、
または再認識するにはとっても良い本ではないでしょうか?
随所、随所に登場する当たり前の事はこの手の本では良くある事ですが
自分がそれを実践できるかどうかは別の問題です。

最後に私が最初に読んだ問題を書いておきます。
「日本に存在する郵便ポストの数はいくつか?」

フェミル推定はこの問題を解くことができる考え方です。
一度読んで実践してみてはどうでしょうか

月曜日, 2月 25, 2008

圧勝ですが

先週は土曜日京都でカジノドライブのデビュー戦がありました。
結果から言えば、圧倒的1番人気にこたえる
圧倒的なパフォーマンスでの勝利という結果でしたが、
以外にも時計が平凡な時計でした。

まあ、時計は展開に左右されるものですから
一概には平凡な時計だから弱いという事はありませんが
あの展開であれば時計でも圧倒的なパフォーマンスで勝利して欲しかったです。

この後は、予定通り戦いの場所をアメリカに移し
ベルモントステークスを目指すようです。

しかし、主戦場がアメリカなのであれば
やっぱり日本に入厩した理由が良く分かりませんね。
日本馬でベルモントS制覇という偉業を達成したかったのですかね。
どちらにしても相手が弱かったとか、日本で走るべきだったなどの
雑音が出ないように頑張って欲しいですね。

C++解説14(クラスについて5)

1. 友達を作ろう

今まで、クラスについていろいろと説明をして来ましたが、
最後にフレンド関数、フレンドクラスについて説明します。
名前の通り、友達関数、友達クラスという事になりますが
実際にどのような機能になるかというと、非公開情報に対して
友達だけには公開してあげようという概念になります。

--------------------------------------------------------------------------------
#include "iostream"


class Human {
private:
int age_;
public:
Human(int InitAge) : age_(InitAge) {}
int getAge(void) { return age_; }
friend void AddAge(Human&);
};

void AddAge(Human& obj) {
obj.age_++;
}

int main(void) {
Human obj(10);
std::cout << "Age = " << obj.getAge() << std::endl;
AddAge(obj);
std::cout << "Age = " << obj.getAge() << std::endl;
}
--------------------------------------------------------------------------------
実行結果
--------------------------------------------------------------------------------
Age = 10
Age = 11
--------------------------------------------------------------------------------

というようにfriendで宣言された関数はクラスのprivate変数に対してのアクセスを許可されています。
friendは関数だけではなく、クラスそのものも友達として宣言する事ができます。

class Human {
private:
public:
friend class sample;
};

このように記述されている場合はsampleはHumanのprivate変数にも関数にもアクセスする事が可能となります。

friendは簡単な文法の癖して以外と難しいのではないかと思っています。
どれをfriendとするかという問題には私Sennaは常にぶち当たっています。
friendとする多くの関数やクラスにfriendとする意味を感じないのです。
上記にはfriend関数の例を記述していますが、はっきり言ってfriendとして記述する必要性はまったくありません。
従って、あまり言い例とお世辞にも言えないのです。

クラス間の関係を精査しどれがfriendクラス、関数となるのか
また、必要がないのか?などど言った問題を整理してからfriendというキーワードを使用する事にしましょう。

クラス説明については一応終了です。

土曜日, 2月 23, 2008

C++解説13(クラスについて4)

1. コピーコンストラクタ

クラスの勉強をする時にきちっと勉強をしないとクラスの文法、継承、コンストラクタ、デストラクタというところまでは
共通して行われるようですが、コピーコンストラクタが抜ける勉強をする人を多く見かけたりします。
何でこのような事態が発生するのか疑問に思い、本屋に駆け込んだところ本によってはコピーコンストラクタを
クラスとは離れたところで説明している本、又はサイトを多く見かけました。これは結構頂けない事だと思います。
C++を勉強している多くの人はC言語を勉強してから始める傾向にあるようです。
そのため、クラスを覚えるとクラスを実際に使い始め関数に渡す事をしたり関数からクラスポインタを戻り値として受け取ったりといろいろな事をやり始めます。
しかし、そこにはコピーコンストラクタという技術が沢山使われておりしらない箇所で危険な処理が動いています。

ここでは、そのような事を防ぐためにコピーコンストラクタの存在についてと実際にどのような時に動く事になるのかなどを検証していきます。

--------------------------------------------------------------------------------
#include "iostream"

class Sample {
public:
Sample() { std::cout << "sample::sample()\n"; }
void View() { std::cout << "sample::View()\n"; }
~Sample() { std::cout << "sample::~sample()\n"; }
};

void func(Sample inObj) {
inObj.View();
}

int main(void) {
Sample obj;

func(obj);

return 0;
}
--------------------------------------------------------------------------------
実行結果
--------------------------------------------------------------------------------
sample::sample()
sample::View()
sample::~sample()
sample::~sample()
--------------------------------------------------------------------------------

デストラクタが2回動いている事が分かると思います。これは、C言語を勉強している人であれば問題ない事実でしょう。
関数func()が終了した時に引数のクラスはスコープ外となりデストラクタが動いているのです。
「!?だったらコンストラクタは何処で動いているの!?」

間違いなく、func()が動く前にコンストラクタが動いています。
ここで動くのがコピーコンストラクタという事になります。

コピーコンストラクタの文法です。
class Sample {
public:
Sample(); // コンストラクタ
Sample(const Sample&); // コピーコンストラクタ
};

基本的にコンストラクタと同じです。
クラスの参照を引数として受け取るコンストラクタという事になります。
これを名にコピーコンストラクタと呼んでいます。
--------------------------------------------------------------------------------
#include "iostream"

class Sample {
public:
Sample() {
std::cout << "(" << this << ")sample::sample()\n";
}
Sample(const Sample& obj) {
std::cout << "(" << this << ")sample::sample(cosnt Sample& obj)\n";
}
void View() {
std::cout << "(" << this << ")sample::View()\n";
}
~Sample() {
std::cout << "(" << this << ")sample::~sample()\n";
}
};

void func(Sample inObj) {
inObj.View();
}

int main(void) {
Sample obj;

func(obj);

return 0;
}
--------------------------------------------------------------------------------
実行結果
--------------------------------------------------------------------------------
(0012FF84)sample::sample() // オリジナルのコンストラクタ
(0012FF54)sample::sample(cosnt Sample& obj) // コピーコンストラクタ
(0012FF54)sample::View() // コピーのView
(0012FF54)sample::~sample() // コピーのデストラクタ
(0012FF84)sample::~sample() // オリジナルのデストラクタ
--------------------------------------------------------------------------------

という事になります。
じゃあ、何でコピーコンストラクタは重要なのでしょうか?
「別にデストラクタが2回動く事ぐらい問題ではないんじゃないの!」
と思ったあなた、C言語から勉強し直して下さい!。
こいつはめちゃくちゃ大きい問題です。
C言語で言うと、mallocしたアドレスを2回freeしている事になります。もう、問題って分かりましたよね。
実際に、コンストラクタでアドレスを確保してデストラクタで開放するプログラムを作成して実験して見ます。
--------------------------------------------------------------------------------
#include "iostream"
#include "cstdlib"
#include "cstring"

class Sample {
private:
char *cp;
public:
// どのオブジェクトか不明のためアドレス情報を出力
Sample() {
std::cout << "(" << this << ")sample::sample()\n";
cp = (char*)malloc(5);
strcpy(cp, "test");
}
void View() {
std::printf("(%p)sample::View()_%p_%s\n", this, cp, cp);
}
~Sample() {
std::cout << "(" << this << ")sample::~sample()\n";
free(cp);
}
};

void func(Sample inObj) {
inObj.View();
}

int main(void) {
Sample obj;

func(obj);
obj.View();

return 0;
}
--------------------------------------------------------------------------------
実行結果
--------------------------------------------------------------------------------
(0012FF88)sample::sample()
(0012FF5C)sample::View()_00913A30_test // cpのアドレスに注目
(0012FF5C)sample::~sample() // ここでフリーされてしまう
(0012FF88)sample::View()_00913A30_<・A // なんじゃこりゃ!
(0012FF88)sample::~sample()
--------------------------------------------------------------------------------

コピーのデストラクタが動いているんも関わらず、オリジナルのアドレスがフリーされてしまいます。
freeされたchar*にアクセスしているため、このような事象が発生してしまいます。
この内容から、コピーコンストラクタが存在しないクラスにおいて
クラスのコピーとは、バイナリーレベルでのコピーが発生している事が推測できます。


そこでコピーコンストラクタによって、同じ内容を格納する新しいアドレスを確保する必要性が出てきます

--------------------------------------------------------------------------------
class Sample {
private:
char *cp;
public:
// どのオブジェクトか不明のためアドレス情報を出力
Sample() {
std::cout << "(" << this << ")sample::sample()\n";
cp = (char*)malloc(5);
strcpy(cp, "test");
}
Sample(const Sample& obj) {
std::cout << "(" << this << ")sample::sample(cosnt Sample& obj)\n";
cp = (char*)malloc(strlen(obj.cp));
strcpy(cp, obj.cp);
}
void View() {
std::printf("(%p)sample::View()_%p_%s\n", this, cp, cp);
}
~Sample() {
std::cout << "(" << this << ")sample::~sample()\n";
free(cp);
}
};
--------------------------------------------------------------------------------
実行結果
--------------------------------------------------------------------------------
(0012FF88)sample::sample()
(0012FF5C)sample::sample(cosnt Sample& obj)
(0012FF5C)sample::View()_00913A40_test // コピー用のアドレスとなっている
(0012FF5C)sample::~sample() // コピーのデストラクタ
(0012FF88)sample::View()_00913A30_test // コピーがfreeされても問題なし
(0012FF88)sample::~sample()
--------------------------------------------------------------------------------

という事になります。
コピーコンストラクタの重要性は理解できたと思います。
他にも、クラス型を返却する時などもコピーコンストラクタが動く事になります。
是非、クラス設計を行う場合はコピーコンストラクタの存在を忘れないようにして下さい。

今週末の競馬

またまたやっちゃいました。
今回の京都記念の私自身の予想はアドマイヤ1、2着の予想でした。
しかもかなりの自信あり予想でした。
3着不明、アドマイヤオーラが元ペーパーオーナーの馬である事などを
馬単:アトマイヤオーラ→アドマイヤフジ
馬連:アトマイヤオーラ-アドマイヤフジ
が予想でした。

後は、その時の状況によりますが
3連単の総流しまで考えていました。

が、本日購入前に見せられた馬体重がアドマイヤフジ20キロ増!
一気に危険レースに格下げされ軸馬変更
アドマイヤフジからウォッカに変えました。
全ては、この判断の失敗です。
ウォッカに変更した段階で投資予定金額は大幅に減らしましたが
かなりのショックです。
なかなか上手く行きません。

明日はフェブラリーSです。
ダイワスカーレットの回避でこれまた軸馬不在となってしまいました。
とりあえず、まだまだ検討中なのですが
現在の本命はワイルドワンダーです。
相手候補はロングプライドとドラゴンファイヤー
3連復まで手を広げた場合はデアリングハート、ブルーコンコルド、ヴァーミリアン、クワイエットデイ
ってところが現在の予想です。

火曜日, 2月 19, 2008

世界でもっとも美しい10の科学実験

正直難しかったです。
私の知識では凄いというところの理解が
おそらく行き届いていないのが現実な気がします。

電子の話になると途端に分からなくなったので
後半に書かれている内容については
頭の中をスルーしている気がします。

ただ前半は地球や重力など受け入れられる内容だったため
それなりに理解できたと思います。

面白かったかという質問に関しては、
面白くなかったとしか答えられないかもしれません。
が、あくまでも私自身の知識ではって事にはなりますが。

毒を売る女

島田荘司さんの短編集です。
短編集という事でボリューム不足である事は否めません。
これはという作品も特にはありませんでした。

タイトルになっている「毒を売る女」は私自身には訴えるものはなく
作品の中で一番好感を持てたのが「糸ノコとジグサグ」ですね。

最近行われていたReader's Selectionにも選ばれていたようですね。
ただ、それでも私は短編集が今一好きにはなれない事実は変わりませんね。

一部、推理小説とはかけ離れた作品ですが「バイクの舞姫」という作品がありました。
島田荘司さんが手がける作品の中では異例の作品のような気がします。
この辺りはファンの心理としては貴重な作品を読んだって感覚はありましたね。

C++解説12(クラスについて3)

1. 継承

クラスの継承について説明します。
継承を行う要因として主に3種類存在すると言われています。

1.1 拡張継承
拡張継承とはどの本でも一番最初に説明がされている継承です。
「人間は哺乳類で...」などど書かれている本があればまさしく拡張継承の説明でしょう。
まあ、今更「人間は哺乳類で...」何て説明どの本もしてないかもしれませんが
ようするに、あるクラスでは機能が不足しているため
追加機能を実装する場合に取る、継承の方法です。

1.2 データ継承
具体的には基底クラスにprotectedで定義した変数を
派生クラスがprivate変数として使用する事を指します。
まさに、データのみを継承するという事になります。
これはそのままですが、いろいろと有効に活用できます。

1.3 インターフェース継承
最後にインターフェース継承です。
オブジェクト指向で多態性(ポリモフィズム)という言葉があります。
C++にはオーバーライドという言葉とオーバーロードという言葉があります。
オーバーライドとはポリモフィズムそのものを指し、
オーバーロードとは同じ名前で宣言されている関数を
引数や返却値などの違いで使い分ける方法です。
ここではオーバーライドの説明を行います。
オーバーロードについては後ほど...


それでは継承の文法です。

class 派生クラス名 : 基底クラス名 {
// 後はクラスの書き方とまったく同じ
}

それでは細かい説明をします。

1.1.1 拡張継承(詳細説明)
「警察官」というクラスを作成してみます。
警察官は人間ですが、人間は警察官ではありません。
なので警察官とは人間の機能に警察の機能を追加する事で
実現できる事になります。

では警察官とはどういった特徴があるかを考えます。

・役職がある
・捜査する
・逮捕する
・拳銃を撃つ

もの凄く簡単ですが、拡張継承の説明としてはこれで十分です。

class Human {
private:
char *Name;
int Age;
char Birthday[9];
public:
Human(char*, int, char*);
~Human();

char* getName(void) { return Name; }
};

class Police : public Human {
private:
int OfficialPosition; // 1:巡査部長 2:警部補 以外:警視
public:
Police(char *InName, int InAge, char *InBirthday, int Position)
: Human(InName, InAge, InBirthday) { OfficialPosition = Position; }
void Search() { std::cout << "捜査してます\n"; }
void Arrest() { std::cout << "逮捕します\n"; }
void ShootGun() { std::cout << "発砲しました\n"; }
char* getOfficialPosition(void);
};

char* Police::getOfficialPosition(void) {
switch(OfficialPosition) {
case 1: return "巡査部長";
case 2: return "警部補";
default: return "警視";
}
}

実際に使ってみましょう。

int main(void) {
Police obj1("semona", 0, "20040101", 1);

std::cout << obj1.getName() << "," << obj1.getOfficialPosition() << std::endl;
std::cout << obj1.getName() << ","; obj1.Search();
std::cout << obj1.getName() << ","; obj1.ShootGun();
std::cout << obj1.getName() << ","; obj1.Arrest();
std::cout << obj1.getName() << "," << obj1.getOfficialPosition() << std::endl;

return 0;
}

ここで注目して欲しいのはPoliceオブジェクトを作成してるにも関わらず、
getName()、というHumanのpublicメソッドを使用しているところです。
これが継承という機能によって実現される事になります。

Police(char *InName, int InAge, char *InBirthday, int Position)
: Human(InName, InAge, InBirthday) { OfficialPosition = Position; }
一応この部分におやっ?っと思った人のために少しだけ解説します。

Police(...) : /* 何か書いてある */ { ... }
この部分ですが、初期化といいます。
初期化と代入の違いは説明しましたが、その初期化に当たります。
何で、こんなところに書くのかを説明したいと思います。

class Base {
public:
Base() { std::cout << "Base::Base()" << std::endl;}
~Base() { std::cout << "Base::~Base()" << std::endl;}
};

class Delived : public Base {
public:
Delived() { std::cout << "Delived::Delived()" << std::endl;}
~Delived() { std::cout << "Delived::~Delived()" << std::endl;}
};

int main(void) {
Delived dObj;

return 0;
}

実行結果
Base::Base()
Delived::Delived()
Delived::~Delived()
Base::~Base()

派生クラスのインスタンスを作成したところ、
基底クラスのコンストラクタとデストラクタがしっかり動いていますね。
しかも、コンストラクタは先に、デストラクタは後に...
これはC++の仕様になります。
つまり、派生クラスは自分のコンストラクタ実行時には
基底クラスをきちっとした形で使用できるという事になります。
でも、基底クラスがこんな感じになっていた場合どっちが動くの?
プログラムは分からない場合は何でも実験です。やってみましょう。

class Base {
public:
Base() { std::cout << "1:Base::Base()" << std::endl;}
Base(int i) { std::cout << "2:Base::Base()_" << i << std::endl;}
~Base() { std::cout << "Base::~Base()" << std::endl;}
};

実行結果
1:Base::Base()
Delived::Delived()
Delived::~Delived()
Base::~Base()


予想通りの結果ですかね。
待って下さいよ。わたくしは2:Baseを使用したいのですが...
でもDelivedのコンストラクタが動くときには終わっちゃってるし
何か、見えてきたって感じですね。
何のためにこんな説明をしているのか!そうですよ初期化ですよ
という事で派生クラスをちょこっと変更

class Delived : public Base {
public:
Delived() : Base(3){ std::cout << "Delived::Delived()" << std::endl;}
~Delived() { std::cout << "Delived::~Delived()" << std::endl;}
};

実行結果
2:Base::Base()_3
Delived::Delived()
Delived::~Delived()
Base::~Base()


他にもこんな使い方が
class Base {
private:
const int CONST_INT;

...
};

このようにconstで宣言された変数には代入は行えません。
しかし代入はできないのですが初期化は当然できます。
だから「Base() : CONST_INT(1) {}」こんな感じで初期化します。
もちろん、こんな初期化が許されるのは、コンストラクタだけです。
理由は簡単ですね。コンストラクタがクラスの初期化だからです。

少し脱線しましたが、以上が拡張継承です。
ここでは人間機能しかなかったHumanというクラスに
Policeというクラスを拡張した警察官というクラス作成しました。
Humanクラスを拡張したため、人間の機能も持っているわけですね。
もし、Policeクラスは基底クラスに犬クラスを選択すれば警察犬ってところですね。


1.2.1 データ継承(詳細説明)

人間ってクラスを作ってきましたが、そもそも人間って
こんな簡単でしょうか?(身も蓋もねえ事、言ってんじゃねえよ!)
すいません。例が無くって、でも進めましょう。

例えば、人間とは男と女に分けられます。
でもって男と女とはまったく違うものです。
それを人間なんて一つのクラスにしてしまったらこの違いをどう表現すればいいのでしょうか?
一つに拡張継承を使って、人間クラスを継承する男クラスと女クラスを作成するという表現方法があります。
しかし、ここではデータ継承を使って表現したいと思います。
今まで、人間クラスで管理していた名前、年齢、誕生日といった項目は人間であれば誰もが持っている項目です。
これらを人間クラスのデータをして保持する事には何も変化はありません。
今までは
class Human {
private:
char *Name;
int Age;
char Birthday[9];
};

として保持し、ここにアクセスするメソッドを提供するという方針でした。
データ継承とはアクセスするメソッドを提供する代わりに、直接継承したクラスにはアクセス権を与える継承方法となります。

クラスにはprivate(非公開情報)、public(公開情報)という他に
protected(継承先には公開、非継承先には非公開)という宣言方法が存在します。
つまり、今までprivateで宣言してきた変数達をprotectedで宣言してやると
いう事ですね。

class Human {
protected:
char *Name;
int Age;
char Birthday[9];
};

これだけですね。すると拡張継承ではPoliceクラスがHumanクラスを継承したので
同様にPoliceクラスにHumanクラスを継承させましょう。

class Police : public Human {
private:
int OfficialPosition; // 1:巡査部長 2:警部補 以外:警視
public:
// Humanの変数には直接アクセスできるため、このような初期化は不要
// Police(char *InName, int InAge, char *InBirthday, int Position)
// : Human(InName, InAge, InBirthday) { OfficialPosition = Position; }
// 新しいコンストラクタ
Police(char *InName, int InAge, char *InBirthday, int Position) {
Name = (char*)malloc(strlen(InName));
strcpy(Name, InName);
Age = InAge;
strcpy(Birthday, InBirthday);
OfficialPosition = Position;
}
};

こんな感じになります。直接アクセスする分すっきりした感じがしますね。
あんまり、難しい話ではないと思います。
ただ、私が考える注意点だけ書いておきます。このデータ継承にはいろいろな使い方があります。
しかし、データ継承を行う場合はデータのみを継承する事をお勧め致します。
データ継承を行い、クラスの機能の継承する何て事をやり出してしまったら
おそらく、自分の頭の中でパニックを起こしてしまう事でしょう。


最後はインターフェース継承です。
ここの冒頭で書いたように、こいつはクラス最大の恩恵を授かる事ができるでしょう。
少しだけ、C言語でこいつの実現を考えて見る事にしてみます。
そもそも、インターフェースプログラミングとは何でしょうか?
実は、使用する側にはインターフェースのみ意識させクラスの中身は考えさせない。
と言ったカプセル化の概念の究極の行き先ではないでしょうか?

たとえば、車を作る事を考えてみましょう。
セダン、RV、ワンボックスいろいろとありますが、要は車を作るという事です。
いろいろと部品の違いはありますが、車を作るという肯定は何も変わりません。
そうです、車を作るというインターフェースに変更はないのです。
だから、「車を作る」というメソッドのインターフェースを使ってセダン、RV、ワンボックスといろいろ作れればいいという事になります。
では実際にどのようなものか、プログラムを書いてみます。

はじめにインターフェースとなるクラスを作成します。

class CarFactory {
public:
virtual void CarCreateExec() = 0;
};

これで作成終了です。
実際に新しい概念が2つ程あります。
1つ目は「virtual」という修飾子がメソッドの前にある事
2つ目はメソッドの後ろに「= 0;」という意味不明な箇所がある所です。

まず、1つ目のvirtualとは仮想関数(バーチャルメソッド)である事を宣言しています。
仮想関数とはこいつはオーバーライドできますよ!って事になります。
オーバーライドとは、直訳すれば「取って代わる。無視する」などの意味となりますがここでは受身で取って下さい。
つまり「取って代えられる、無視される」って感じでしょうか
そして2つ目の「=0;」ですが、純粋な仮想関数である事を指しています。
純粋な仮想関数?
当然、こうなっても仕方ないですわね。
はじめに、仮想関数を説明してから純粋仮想関数について考えてみますね。

とりあえず、さっきのCarFactoryを拡張しましょう。

#include "iostream"

class CarFactory {
protected:
char *CarName;

public:
void PreCarCreate() {
std::cout << "車を作り始めます\n";
}
virtual void CarCreateExec() {
char *CreateCarName = "自動車1";
CarName = CreateCarName;
}
void SufCarCreate() {
std::cout << CarName << "の完成です\n";
}
};

int main(void) {
CarFactory *obj = new CarFactory();

obj->PreCarCreate();
obj->CarCreateExec();
obj->SufCarCreate();

delete obj;

return 0;
}

実行結果
車を作り始めます
自動車1の完成です


まあ、何て事はないですよね。
では次に「virtual」で宣言されている関数をオーバーライドします。

#include "iostream"

class RvCarFactory : public CarFactory {
public:
virtual void CarCreateExec() {
char *CreateCarName = "RV車1";
CarName = CreateCarName;
}
};

int main(void) {
CarFactory *obj = new RvCarFactory(); // ここがポイント

obj -> PreCarCreate();
obj -> CarCreateExec();
obj -> SufCarCreate();

delete obj;

return 0;
}

実行結果
車を作り始めます
RV車1の完成です

こんな結果になります。理解できましたかね? すべてのポイントは継承なんですが...
派生クラス(継承したクラス)は基底クラスの公開関数/変数、
継承先公開関数/変数を自分のものとか、言ってきましたが正しくは派生クラスの中に基底クラスの内容が含まれるという言い方が正しいかもしれません。

class Base { ... };
class Deli1 : public Base { ... };
class Deli2 : public Deli1 { ... };

となっている場合、

class Base
Baseクラスの内容

class Deli1
Baseクラスの内容 + Deli1クラスの内容

class Deli2
Baseクラスの内容 + Deli1クラスの内容 + Deli2クラスの内容

こんなイメージです。でっかく×2なっていっているという事です。
で今回ポイントになっている以下の文ですが、
CarFactory *obj = new RvCarFactory();

上の例でいくと
Base *obj = new Deli1();
という事になりますね。でどのような意味になるかというと*objには間違いなくDeli1の内容が格納されています。
しかし、objとはBaseポインタ型です。という事は、Baseクラスが提供している方法でしか
Deli1にアクセスできないという事になってしまいます。
でも間違いなくDeli1クラスのオブジェクトを作成しているため「RV車1の完成です」という結果になったのです。
Deli1のCarCreateExecは「RV車1」のアドレスを代入しているでしょ!

何か、いろいろ言ってるけど使えなくね~~~!。なんて思ってしまったら「ばかもん!」って言われるのですよ。

ここが最大のポイントですから。ここって何の説明でしたっけ?そうですよ。インターフェースプログラミングですよ。
インターフェースプログラミングとはインターフェースを基底クラスに宣言して、そのインターフェースを守って派生クラスを実装するって事ですよ。

今回はオーバーライドを説明するために、基底クラスに関数の実装を用意しましたが、
RV車を作成する特化したクラスがあったのですから自動車、ここではセダンだとしますね。
自動車を作成する特化したクラスがあれば良いという事になります。
またCarFactoryクラスはインターフェースに特化させてしまえば関数の実装は不要という事になります。

この「インターフェースに特化させるため、関数の実装は行いません」
という宣言を純粋仮想関数で行います。

つまり、以下のクラスのインスタンスは作成を行う事はできません。
なぜなら、CarCreateExecには関数の実装が行われていないため
実際にどれを動かせば良いのか分からないという事になるからです。
ここまでの内容を踏まえて、RV車とセダン車を作成するクラスを作成します

// インターフェース専用です
class CarFactory {
public:
virtual void CarCreateExec() = 0;
};

class RvCarFactory : public CarFactory {
public:
void CarCreateExec() {
std::cout << "RV車を作成しました\n";
}
};

class SedanCarFactory : public CarFactory {
public:
void CarCreateExec() {
std::cout << "セダン車を作成しました\n";
}
};

int main(void) {
// ここではセダン車を作成しますが、ここ1行を書き換えてしまえば
// RV車を作成する事ができます
// CarFactory *obj = new RvCarFactory();
CarFactory *obj = new SedanCarFactory();

obj -> CarCreateExec();

delete obj;

return 0;
}

実行結果
セダン車を作成しました


結構いろいろな事が思いついてきたでしょ?
ここでは、簡単なインターフェースプログラミングについて触れました。
こいつをものにする事ができればC言語とは違うまったく新しいC++の世界が見えてくると思います。

余談ですが、デザインパターンと言われているパターンを実装する場合
このインターフェースプログラミングは必須な知識/テクニックです。

金曜日, 2月 15, 2008

IPOD TOCH

IPOD TOUCHってめちゃくちゃかっこいいですよ。
16Gで容量が足りなかったため見送っていましたが
32Gの発売で購入に踏み切りました。

まだまだ使いこなしてはいませんが、音楽を聴く上での
操作等は問題ないですね。
前のIPODと比べると、ホイールではなくなったため
感覚での操作は行えなくなりましたが
まあ、そこまで大きい問題ではありません。

家の無線LANがWiFi規格ではないので総取替えする予定です。
その前にFONなどが使えないかどうかを調査中です。

今のところかっこよさもあるので最高ですね。

火曜日, 2月 12, 2008

家が全滅

子供が3人とも熱を出してしまい、全滅状態です。
最初は1人だったのですが、今の状況ではどうしてもうつってしまいます。
週末は家に居るように心掛けようとも思いましたが
逆にストレスになってしまったところもあるようで
ご飯を外で食べたいとの事だったため食事に出かけました。

本人達は満足したようですが、風邪の状況は良くなる事はありませんでした。
今日で4日目になります。
長女は回復傾向にありますが、次女は悪化しているような気もします。
最悪なのが、3ヶ月にも満たない三女が熱っぽいところですね。

見ているこっちも辛いので早く治ってくれる事を祈るのみです

木曜日, 2月 07, 2008

C++解説11(dequeとlist)

「deque」と「list」は「vector」と同じ順序コンテナと呼ばれるものです。

「deque」は「vector」に対して配列の先頭に要素加する事も
高速で実現ができるコンテナで
その他については「vector」と同一と考えて問題ないでしょう。
これだけを書くと「vector」は不必要で「deque」だけ存在すれば良いのではないか?
という感じもします。

実際問題、多くのケースは「deque」だけで問題ないと思います。
逆の言い方をすれば、「vector」だけで
問題ないケースがほとんどかもしれません。
どのようなプログラムを記述するかに依存しますが
配列の先頭に要素追加を行う必要性がないのであれば
「vector」で良いのではないかというのが
私の考え方ではあります。

もし、後で配列の先頭に要素追加を行う必要が存在した場合
「deque」と「vector」の関係であれば、よっぽどの事がない限り
配列の定義部分のみを変更してしまえば動くのではないかと思います。
まあ、この事態は設計ミスという事になりますが。
(言語が設計ミスをカバーするってもの変な話です)

「vector」を使えれば、間違いなく「deque」は使用できます。
以下に違いを示しますが大きい問題ではない事が分かると思います。

「deque」のみ存在する関数
pop_front() 先頭要素を削除する
push_front() 両端キューの先頭に要素を追加する

「vector」のみ存在する関数
capacity() ベクタが保持できる要素数
reserve() ベクタが保持できる要素数を設定する

相互変更をする場合に上記関数を使用していなかった場合
それぞれ置き換える事が可能という事になります。
「deque」を使用していて「pop_front」「pop_back」を
使用していないのは、ちょっと理解できないですね。

「vector」が準備している「capacity」、「reserve」というものは
ほとんど使わないのではないでしょうか。

「reserve」を使用するのは本当の意味での
高速プログラムを実現する時です。
「vector」は要素を無限(これは言い過ぎですがまあ嘘にはならないかな)
に追加できるのが特徴ですが、その裏では「メモリを確保」して、
「確保したメモリに既存のデータをコピー」してといった
容易に想像できる処理が動いています。

しかし、この確保するメモリを多くすれば拡張回数を減らす事ができます。
かと言って、多すぎるメモリの確保は
獲得コストが必要以上に要する事態が発生します。

つまり通常発生するデータの格納個数をA、
突発的な事故が発生しデータ量が増えるケースを予期した戸数をBとした場合
一番最初に「A」の分だけ「reserve」してしまえば
無駄なメモリの確保、コピーが減るという事になります。
しかも多くの場合、領域の確保、データのコピーというものは発生しないでしょう。
このような対策を「reserve」を上手く利用する事で行える事になります。

しかし、この処理にコストがかかると言っても
何秒といった時間が係るわけでもないため
ここまで性能を追求するプログラムを作成する
機会というのは少ない気もします。

要するに、「reserve」など使う機会がほとんどないですよ!
って事を言いたいのです。
それは「capacity」にも言える事で、私が思うに「capacity」って
一度も使った事が無いかもしれません。
覚えている限りではないです。(練習は除きますよ)

この事から、「vector」から「deque」にコンテナを移す事は
多くの場合で容易にできる事が分かると思います。

「list」は多少2つに比べると特徴に違いがあります。
最大の違いは「ランダムアクセス」不可というコンテナであるところです。
「ランダムアクセス」とは直接アクセスだと考えて下さい。
イテレータのところで扱った「random_iterator」が扱えないという事です。
つまり配列のインデックスを指定する際に「[]」という演算子を指定しますが
「list」にはそれができないという事になります。
これだけでもかなりの特徴があると思います。

vector v;
deque d;
list l;

v[0]=1;
d[0]=1;
l[0]=1; ← 出来ない!

という事です。何故か?というと「list」というコンテナが
「ランダムアクセス」を行われることを前提に設計されていないからです。
「ランダムアクセスを行えるようにする」場合と
「ランダムアクセスを行えなくても良い」場合では
何が違うのかというとメモリが連続領域である必要がないというところです。

つまり配列サイズが10となっている「a」の5番目の要素を削除したい場合
配列を確保するメモリが連続領域である必要のある
「vector」「deque」については、5番目の要素を削除後に
それより後ろに格納されている全てのデータを1つ前に移動させる必要があります。

それに対して「list」は連続領域である必要がないため
「N番目のデータの次はN+2番目である」
「N+2番目のデータの前はN番目である」という
2つの処理を行う事で要素の削除が行えることになります。
逆も同じで配列途中に要素を追加する事を考える場合、
「vector」「deque」は追加する要素位置以降に存在する要素を
全て追加する要素分後ろにずらしてから、要素の追加を行います。
「list」は「N番目のデータの次はM番目である」
「N+1番目のデータの前はM番目である」という
2つの処理を行う事で要素の追加が行えます。

データの追加、削除を配列の途中に頻繁に行う場合、
「list」というコンテナは非常に有用です。
少量のデータであれば、気にするポイントではないかもしれませんが
大量のデータを扱う場合にはパフォーマンスなど
コンテナを選択した段階で決まっているようなものです。
どんなに、高速なプログラムを組んでも
設計が間違っていれば高速にはなりきれないという事です。

扱い方は「vector」「deque」と同じです。
これがSTLの素晴らしいところですね。

水曜日, 2月 06, 2008

C++解説10(iterator)

イテレータとは汎用ポインタです。
っていうと間違っているような気もするのですが
そうやって覚えて問題ないと思います。

イテレータの簡単でかつ最も多様する方法に
STLが提供するコンテナの操作、参照といった事があります。

イテレータにはいくつかの種類が存在し
これを正確に理解する事で単純なバグを抑止する事ができると思います。

1.forward_iterator
前方イテレータや前進イテレータなどと呼ばれているもので
「++」というインクリメントのみの移動が可能なイテレータです。
イテレータの参照、イテレータへの更新といった操作が許されています。
参照ができるという事は比較演算子である「==」「!=」などが使用でき
更新が行えるという事は代入演算子である「=」が使用できるという事です。

2.input_iterator
forward_iteratorに対して、更新系の操作(要するに代入)を奪ったものが
input_iteratorと言います。
このイテレータに対して、代入演算子を使用するとコンパイルエラーとなります。

3.output_iterator
forward_iteratorに対して、参照系の操作を奪ったものが
output_iteratorと言います。
参照系の操作が出来ませんので、if文で使用したり、for、whileなどの終了条件に
使用する事もできません。

4.bidirectional_iterator
forward_iteratorに対して、デクリメントの機能を追加したものが
このbidirectional_iteratorと言い、双方向イテレータと呼ばれます。

5.revese_iterator
forward_iteratorに対して、インクリメントを行うと後方に進むのに対して
このrevese_iteratorはインクリメントすると前方に進みます。
この「reverse_iterator」と「forwaed_iterator」については
どちらのイテレータを使用しているかを認識していないと
進む方向が同じプログラムでも変っている事になります。

6.random_iterator
最後に、全ての機能を兼ね備えるのがrandom_iteratorと言われるものです。
bidirectonal_iteratorに何の機能が加わるかというと「[]」での参照機能です。
つまり「[]」という演算子でアクセスを行えるコンテナについては
使用されているイテレータがこのrandom_iteratorという事になります。


実際に「vector」でイテレータを使用してみます。

vector v;
のイテレータとして
vector::iterator i;
という宣言方法で「i」というイテレータを宣言します。

イテレータの型を特定するのが目的になります。
ポインタ宣言を行う場合に「char*」なのか「int*」なのか
といった事を宣言しています。

これはC言語の特徴の1つと言ってよいかもしれません。
理由は簡単で配列はポインタで表記されるのがC言語です。

int n[10];
char c[10];

というような2つの配列が存在した場合、
0番目の要素と1番目の要素の場所の間にはどのくらいの距離があるのでしょうか?
配列とは連続しているメモリー領域を約束されていますので
0番目の要素と1番目の要素が隣り合わせである事は間違いありません。
0番目にしても1番目にしても通常の「int」として扱う事ができますから
2つ間とは、配列の型のサイズである事が分かります。
つまり移動量を特定するためには、どの型であるかを知る必要があります。
そのため、「int*」「char*」と言った宣言が必要になります。
イテレータもこれと同じ理屈で型が必要という事になります。


前回あいまいのまま終わらせた中に「vector」で使用できる
アルゴリズムが他にも沢山ある事を書きました。
それを解説しながらイテレータというものを実際に使用してみます。


「vector」には「begin」「end」という
最初と最後のイテレータを返却するメソッドが存在します。

これで一番簡単なプログラムは「vector」の要素として管理されている
最初から最後までの全ての要素の値を出力するプログラムです。
それは以下の通り書くことができます。

vector v;
vector::iterator i;

for(i = v.begin(); i != v.end(); ++i) {
cout << *i << ","; } 「*i」などどいう記述はまさにポインタそのものです。 C++では様々なアルゴリズムが登場しますが ほとんどが 「i = v.begin()」~「 i != v.end()」 という考え方が基本となります 要するに「end」が指すのは、最後の位置ではなく 「最後+1」の位置という事になります。 次に「insert」です。 vector v1;
vector v2;

2つの「vector」の配列が存在し、

「v1」の後ろに「v2」を挿入する場合

v2.insert(v1.end(), v2.begin(), v2.end());

と記述する事ができ

「v1」の先頭に「v2」を挿入する場合

v2.insert(v1.begin(), v2.begin(), v2.end());

と記述する事ができます。


また途中に挿入する必要がある場合は

for(vector::iterator i = v1.begin(); i != v1.end(); ++i) {
if (*i == 挿入する配列の後にしたい要素) {
v1.insert(i, v2.begin(), v2.end());
}
}

と記述すれば良いという事になります。
これは本当に素晴らしい事です。
C言語からの進化、又はSTLで記述しないC++プログラム
と比べてもその素晴らしさは圧巻です。

「erase」もまったく同じ考え方で関数そのものは2つの引数で定義されています。

iterator erase(iterator pos);
iterator erase(iterator s_pos, iterator e_pos);
イテレータを指定する事でこのアルゴリズムも一瞬にして手の中に入っていますのです。

今回は「vector」を例に少しだけイテレータの世界に入りました。

火曜日, 2月 05, 2008

C++解説9(vector)

今回はSTL(Standard Template Library)を使用します。
最初は一番馴染み易いものが良いのでvectorという
シーケンスコンテナを扱ってみます。

「vector(べクター)」とは可変長配列を指します。
簡単に言えば、配列を宣言する上で必要だった
要素数のMAXを指定する事なく
いくらでも要素を追加する事を可能にした配列です。

・最大の特徴はランダムアクセスが可能である
・末尾へのデータ追加、削除については「O(1)」を出す。
・C言語の配列と同様の考え方ができる

特徴としてはこんなところでしょうか?
では実際にvectorを使ってみましょう。

// 「vector」の宣言
vector v;

// 要素の代入
for(int i=0; i != 10; i++) {
v.push_back(i);
}

// 要素数の出力
cout << v.size() << endl;

// 末尾への要素削除
v.pop_back();

// 末尾への要素追加(配列のMAXは気にする必要なし)
v.push_back(100);

// 要素参照
for(unsigned u=0; u != v.size(); ++u) {
cout << v[u] << ",";
}

上の機能をC言語で実現した場合の違いを書かなくては
何が凄いかは分かりづらいかもしれないですね。

まず、要素数を抑えるために別の変数を用意する必要があります。

int v[10];
unsigned size=0;

// 要素の代入
for(; size != 10; size++) {
v[size]=size;
}

// 要素数の出力
cout << size << endl;

// 末尾への要素削除
size--;

// 末尾への要素追加(配列のMAXは気にする必要なし)
size++;
if (size < 11) {
v[size]=100;
} else {
cout << "要素数オーバー" << endl;
return -1;
}

// 要素参照
for(unsigned u=0; u != size; ++u) {
cout << v[u] << ",";
}
return 0;
}

こんな感じになります。
あんまり凄さは分かんないですかね?

size++;
if (size < 11) {
v[size]=100;
} else {
cout << "要素数オーバー" << endl;
return -1;
}

いろんな意味で、この部分が必要なくなるって事が
もの凄い事なんですよね。

「vector」とは一つのオブジェクトですので
様々な情報も保持しています。

配列の情報として一番重要なのは要素数という事になります。
それも別の変数で管理する必要はなく
「v.size()」と記述する事で情報の取得が行えます。
ここがオブジェクトの素晴らしいところです。

さらに「vector」には数々のアルゴリズムが用意されています。
配列を扱う上でメンドクサイ作業の一つに
配列の途中に要素を挿入する、又は途中の要素を削除すると
いった作業がありました。
純粋にアルゴリズムと言われるプログラムを書いていたと思いますが
「vector」にはこの辺りも汎用プログラムとして既に存在します。

v.clear();
と記述するだけで、配列内の全ての要素が削除されます。
この作業を行う方法はいろいろとあったと思います。
外部で管理している要素数に「0」を代入する
といった作業と同じ感じです。

シーケンシャルなコンテナである配列への要素追加は
末尾に追加されるのが一般的です。
例にも出てきましたが

v.push_back(val);
は要素の追加を行います。

a[配列要素数のMAXを管理している変数]=val;
配列要素数のMAXを管理している変数++;

こんな感じの処理を行っています。

逆に要素を取り出しするのが
v.pop_back();

配列要素数のMAXを管理している変数--;
ってところでしょうか。

イテレータという考え方を覚えると、
このコンテナに実装されているアルゴリズムが
さらに沢山ある事が分かります。

次回はイテレータという考え方に触れて
この「vector」の続きを少し書きたいと思います。

スーパーボール

今年はNFLを結局1試合しか見ませんでした。
ニューイングランドの試合はまったく見なかったです。
サイトで結果のみ確認していましたが
負けない負けないの連続で気が付けばスーパーボールへ。

私の記憶ではこんなチームなったのですが
案の定その通りで、スーパーボールに勝利すると
1972以来の快挙となったようです。
1972といったら、私がこの世に生を受ける前ですから
もの凄い事だと感じます。

ニューイングランドが勝つものだと思っていたのですが
結果はまさかの敗退。

しかも残り1分を切ってからの逆転劇は
創られたドラマのような展開です。

勝利したのはニューヨークジャイアンツで偉大な兄、
ペイトン・マニングの弟であるイーライ・マニングが
スーパーボールMVPに選ばれました。

残念ながら感動の試合を生中継で見る事もできず
まだ録画したものも見ていない状況です。
今年は例年以上にNFLを見る事ができませんでした。

月曜日, 2月 04, 2008

奇跡が...

土曜日は、何気ない一言から奇跡が起きてしまいました。
週末は子供を何処かへ連れてって上げたいと思っているのですが
なかなか、この寒さでは良い場所もないのが現実です。
今週から東京競馬場で開催される事もあり
「競馬場に行こう」と言う事で生後2ヶ月の子供を連れて
競馬場に出かけました。
生後2ヶ月のデビューは次女を超える速さでのデビューです。
競馬場にはエアーで膨らんだ大きい遊ぶものがあり
長女はそれが大好きで、それをやらせるのが目的でした。

次女は去年の東京競馬の時にデビューさせたのですが
少し、怖がっていて今一だったようでしたが
今回は非常に面白そうに遊んでいました。

乗馬もさせた後に馬券予想です。
ここで奇跡が...

メインの東京新聞杯です。
私の馬券はまったく外れました。かすりもしません。
が、、、嫁の馬券が3連複でヒットしているではないですか!!
奇跡の50万馬券を的中です。
興奮が抑えられない、私と嫁はびっくりです。
もちろん、子供は何が起きているのかは理解していません。
夢のような出来事でした。

その足で嫁の実家に向かった私たちは、温泉に浸かり
有意義な一日を過ごす事ができました。

翌朝、外を見ると一面が銀世界となっていました。
そのため、帰りが大変な事になってしまいました。

子供達は雪を楽しんでいましたが、私達は子供3人を
引き連れているから一苦労です。

家に帰った後に、マンションの庭で
3歳と1歳の2人の娘と雪だるまを
家族分の5つ一緒に造ってしまいました。
ほとんど、自分一人で造りましたが...

それでもかなり喜んでいたので、それなりに満足した雪遊びでした。
こうやって奇跡のような週末は終わりました。

金曜日, 2月 01, 2008

魍魎の匣

この人の本は本当に面白い。
私の感想としては本編が面白いというよりは
本の中で語られる哲学的な事が面白い本ですね。

前回の「姑獲鳥の夏」の時は仮想現実の話でしたが
今回は宗教、超能力者、霊能者といったものに対する
考え方が沢山書かれていて、この部分にかなり共感を覚え、
また一つ考え方の幅が広がった気がします。

ストーリーは正直面白いとは言い難いというのが意見ですね。
話としては非常に重たいので映画化されるようですが、人気はどうでしょう。
ただ、最後に謎が一つ一つ明かされていくシーンは驚きの連続ですね
そもそも、謎を解くヒントが隠されていたのでしょうか?
まあ正直、分かりませんでした。

個人的には京極堂が話す「宗教、超能力者、霊能者」のところは
削ってほしくないです。
一番のこの作品に印象を受けた個所ですから。

魍魎という言葉を辞書で引いてから読むとまた面白いかもしれません。

兎に角長編です。読み始める前に人によっては心の準備もいるかもしれません。

木曜日, 1月 31, 2008

C++解説8(template)

今回はtemplateです。はっきり言ってこれには感動します。

1. templateとは
私自身がC++で最も素晴らしい機能と思っているのがtemplateです。
templateというのは直訳すれば「型」という意味です。

言葉の定義をする意味で「型」を辞書で引くと
(1)外見に現れたかたち。かっこう。《形》
(2)相対的な特性によって区別される性質や形態。タイプ。《型》
(3)同種類の物を幾つも作る時、基にする枠や紙。ひながた・鋳型・型紙など。《型》

このあたりで良いでしょう。
C++で言うtemplateとは(3)が一番しっくりくると思います。

template機能は「基にする枠」を作成するという機能になります。
枠ですから、それは関数かもしれませんし、クラスかもしれません。

具体的にする1段階前の抽象的な状態で枠を作成し
使用する時に具体化するという事になります。


2. 型が違うだけの処理はtemplateで書け!
C++で型というと「int」「char」「long」などがそれに該当します。
「型が違うだけの処理」とは「int、longという型だけが違う処理」を指します。

ここでMAXという関数を作成します。
とりあえず「int」という型で作成すると

int max(int lhs, int rhs) {
return (lhs >= rhs ? lhs : rhs);
}

こんな感じですね。
float、double、char、longなど様々な型においても
同じように作成する事が行えます。

少し、C言語に慣れている人であれば
#define MAX(X,Y) X >= Y ? X : Y

なんてマクロを作成するかもしれませんね。
しかし、マクロは型の安全性においてまったく頂けないため
C++の型の安全性という考え方にはまったく合わず
型毎に作成するなどはメンドクサクテ行えません。
そもそも、maxなんて単純な関数だから良いですが
複雑な関数だった場合、かなり不都合が生じる事でしょう。


templateはこのような問題を解決してくれる考え方、機能となります。

templateの文法を利用して上の関数を書き直します。

template
T max(T lhs, T rhs) {
return (lhs >= rhs ? lhs : rhs);
}

という事になります。
難しい事は一つもありません。
型の箇所を「T」という型で統一し、それを「template」と書く事で
template宣言している事を示しているのみです。
また、使う場合も以下の書き方となります。

int n1=1, n2=2, n3;
long l1=1, l2=2, l3;

n3=max(n1,n2);
l3=max(l1,l2);

n3=max(n1,n2);
l3=max(l1,l2);

cout << "n3 =" << n3 << endl;
cout << "l3 =" << l3 << endl;

これを見ると一目瞭然ですが
呼ぶ方は何も気にする必要がないという事です。
これで、templateから対応する型に対して関数が作成され、
実行時にそれが動作する事になります。


max関数を眺めると「>=」という演算子しか使用していませんから
「>=」だけ定義されていれば型が何であれ使用ができるという事になります。

これが最大限発揮するのは対象がユーザー定義型となった場合でしょう。

たとえば、以下のような動物クラスがあります。

#include
#include

using namespace std;

class CAnimal {
string sName;
long nSpeed;

public:
CAnimal(string InName, long InSpeed = 1) {
sName = InName;
nSpeed = InSpeed;
}

CAnimal() {
sName = "";
nSpeed = 0;
}

bool operator >=(CAnimal &rhs) {
return (this->nSpeed >= rhs.nSpeed ? true : false);
}

string GetName() {
return sName;
}

};

これは、名前と移動スピードを管理しているだけのクラスです。
さらに「>=」という演算子をオーバーロードしていて
移動スピードの速い、遅いで演算子を評価しています。
つまり、max関数にこの動物クラスを与えると
スピードの速い動物を特定する事になります。
それでは実際に使ってみます。

template
T max(T lhs, T rhs) {
return (lhs >= rhs ? lhs : rhs);
}

int main(void) {
CAnimal obj1("Lion", 10);
CAnimal obj2("Tiger",15);
CAnimal obj3;

obj3 = max(obj1, obj2);
cout << obj3.GetName() << endl;
}

この実行結果は「Tiger」となります。

このようにユーザー定義型にも、templateとは使用できるのが
非常に効果的で、効率的なプログラムを作成する事ができます。
これの詳しい話は「STL」のところが一番良いと思いますので
「STL」の方で詳細を書きたいと思います。

3. 真髄はこちらにある。クラステンプレート
関数に対して、クラスのテンプレートという事になります。

文法は関数の時と同じで、テンプレート化する型を前方で宣言をし
後はその記号を使用して書き進めるという事になります。

C言語の型をラップするクラスをテンプレートで作成してみます。

template
class Rapper {
T m;
public:
Rapper (T in=1) { m = in; }

void SetValue(T in=1) { m = in; }
void Add (T in=1) { m += in; }
void Subtract(T in=1) { m -= in; }

T GetValue () { return m; }
};

簡単すぎるラップクラスです。
値を直接書き換える事ができません。
基本的に加算、減算のみが行えます。

これは「int,long,float,double」などC++に存在する
プリミティブな型をラップする事ができます。

Rapper IntRapper(10);
Rapper LongRapper(10);
Rapper FloatRapper(10.1);
Rapper DoubleRapper(10.1);

IntRapper.Add();
IntRapper.Subtract(4);
IntRapper.GetValue();
こんな感じで使用します。


クラステンプレートそのものは特に難しい話ではありません。
また、テンプレート引数とは1つである必要もなければ
関数の引数を与えるように使用する事も可能です。

template
class Rapper {
T m[MAX];
int nPos;
public:
Rapper () { nPos = 0; }

void SetValue(T in) { m[nPos] = in; }
void Add () { nPos++; }
void Subtract() { nPos--; }

T GetValue () { return m[nPos]; }

void PrintMax() { cout << "MAX=" << MAX << "\n"; }
};

これは、配列の要素数MAXをテンプレート引数で与えられる事になります。
「= 10」が表しているのはデフォルト引数ですから
引数として何も与えなければ「10」がMAXという事になります。

Rapper IntRapper1;
Rapper IntRapper2;

IntRapper1.PrintMax();
IntRapper2.PrintMax();

この実行結果は
MAX=10
MAX=20
となります


4.templateの特殊化
templateには特殊化という考え方が存在します。
ある特定の条件において特別な処理を行うケースを指します。

「copy」という関数について考えます。

template
void copy(T *lhs, T *rhs) {
*lhs = *rhs;
}

int main(void) {
int i = 0,j = 1;
cout << "(i,j)=(" << i << "," << j << ")\n";
copy(&i,&j);
cout << "(i,j)=(" << i << "," << j << ")\n";

char a[10], b[10];
memset(a, 0, 10);
memset(b, 0, 10);
memcpy(b, "test", 4);
cout << "(a,b)=(" << a << "," << b << ")\n";
copy(a, b);
cout << "(a,b)=(" << a << "," << b << ")\n";
}

この実行は期待する通りにはいきません。
文字列のコピーは代入演算子(=)では処理ができないからです。
そこで、char型についてだけ特殊なコピーを用意する事にします。

template<>
void copy(char *lhs, char *rhs) {
memcpy(lhs, rhs, strlen(rhs));
}

これはtempalte関数コピーを「char」についてのみ特殊処理を記述した事になります。
これをtemplateの特殊化と言います。
この特殊関数が存在すると上のプログラムは期待通りに動作すると思います。


今回説明をしたtemplateとは、
今後登場するSTLの説明には知識として不可欠となります。
書くことでイメージがはっきりすると思いますので
プログラムを作成する事をお勧めします。

酒が飲めない

最近めちゃくちゃ酒が弱くなった。
飲んだ量が以前の半分にも満たないにも関わらず
ほろ酔い状態になってしまう。
次の日は二日酔いではないが、体にだるさが残っている。

これはまずいと思うのだが、どうしようもないのも事実。
何か、悲しくなってしまいます。

ただ、ここ2回酔っ払っている店が同じであるため
そこの酒が非常に強いのではないか?
という思いもあるが、それにしても全てが原液だったとしても
以前であれば、飲めた量だと確信してしまう。

飲みすぎは体に良い事ではないが、
飲めないのも心に良くないと思ってしまいます。

火曜日, 1月 29, 2008

選択の基準

生活をしていると、様々な場面で物事を選択する場面に出くわす。
私が思うには選択した結果が正しかろうが、間違っていようが
ほとんどの選択状況においてはたいした問題は発生しない。

だからほとんどの選択は直感的に行っている場合が多いし
それが間違っていたところで「間違ってたんだ」くらいにしか思ってない。

しかし、それが非常に重要な結果を生み出す場合もある。
正しければ良いのだが、間違っていた時は、後悔する事もあったりする。

そこで選択を行う場合、必ず以下の事を
必ず満たす選択肢を優先して選ぶことにした。

優先順番は項番が小さいものを優先とする。

1.子供に取って良い方を選択する。
 これは子供が望むものというわけではない。
 私自身が子供の気持ちにたってそれがベストだと思ったものを選択する

2.自然である方を選択する
 ほとんどの選択肢は、自分、相手、会社などの利益が考えに入ってきて邪魔をしている。
 これを無くすには、それらを全て捨てる必要がある。
 「そこで、それを選択する事に無理がないか?」という事を必ず自問する。
 ここで言う、無理とは「それが自然ですか?」という意味で考える
 ※これはテレビ東京の「カンブリア宮殿」だったと思いますが、そこに出演した誰かの言葉です。
   非常に共感を覚えたため、自分の中での格言としました。


とりあえず、この2つです。
これは不変にする事はまったく意味がないので
常に共感を覚える言葉、考え方、などがあれば変えて行きます。
変化し続ける事が一番大事なので。

月曜日, 1月 28, 2008

アドマイヤメインは...

今回のAJCCは惨敗でしたね。
エアシェイディとアドマイヤメインの2頭軸での勝負だったのですが
3コーナーから4コーナーにかけて早々と失速。
買い続けているエアシェイディの
待望重賞初勝利にあやかる事はできませんでした。

それにしてもアドマイヤメインって...
騎手が悪いのか、調教師が悪いのか、馬が悪いのか
やっぱり馬主が悪いのか...

あの負け方はショックですね。
本当に強い馬だと思っているのですが結果が付いて来ませんね。
気性的に難しい馬なのですかね。
やっぱりこの馬の強さを引き出せるのは武豊だけなのですかね。
アドマイヤの馬に武豊が騎乗する事もなくなってしまいましたから
残念ですが、この馬がレースを勝つ事はもう難しいのかもしれませんね。

しつこいですが、あの負け方はショックです。
直線までも持たないとは。

エアシェイディは逆に完璧でしたね。
さすがは後藤騎手です。
正直、直線に向いた時には出るところがないかなっても思ったのですが
馬の強さ、騎手の度胸など完璧にハマった感じがしました。

この馬は横山騎手よりは、確実に後藤騎手の方が向いている気がします。
次は、何処を目標にするのかは分かりませんが頑張って欲しいですね。

馬券はアホな事に京都11Rと中山11Rを間違って購入する始末。
余計な投資もかさみ、不必要な大負けでした。

付きがない週末

先週末は去年購入したパソコンのCDドライブが壊れるという
ハプニングが発生してしまいました。

DVDのリッピングソフトをインストールして
使用していたら、突然の無反応です。

メーカーに問合せしたところ、
どうにもリッピングソフトというところに
引っかかったのでしょうね。

いろいろと試しましたが、復旧せず
再セットアップを行う事になってしまいました。
しかし、2時間かけて行った作業はそれでも復旧せず
結局メーカー保証中であるため修理になりました。

本日サポートから電話があって、
パソコンを取りに来る日程等の調整を行ったのですが
その中で、「お客様の過失があった場合は有料になる場合もある」
でもって「修理を拒否した場合でもお金がかかる」とのお話。

まったく意味が分からなかった私は
「過失とはどのような事を指すのですか?」と質問をすると
「お客様の場合はリッピングソフトをインストールしたりしていますので...」
とのお話...
「インストールしてはいけなかったのですか?」と続けて質問をすると
「そうではないのですが...」と良く理解のできない応対。

「では過失とはどのような事を指すのですか?」と初めの質問に逆戻り...
で向こうの答えは変わらずで同じ。

まったく日本語が通用しないサポートの人間に
「他の人に代わってくれ」とお願いすると
「他の人間に代わっても同じです」とのお答。
本当に人を怒らせるのが上手い人です。

だんだん頭に来た私は、最後には電話を切ってしまいました。

どうして、こんな人間にサポートデスクをやらせるのか意味が不明です。

明らかにリッピングソフトが原因だと言いたげでしたね。
リッピングソフトがきっかけでいろいろな犯罪が発生しているのは認識していますが
リッピングソフトを否定する事はやめて欲しいですね。

もし、インストールして事がハード障害を発生させ
それが使用者の過失と言うのであれば、
メーカーとしてインストールするなと言う義務があるのではないかと...

さらにメーカーサポート期間中であるにも関わらず、
故障の修正が有料なのは一歩譲って良いとしても
「有料と判断された時に、お金を出してまで修理する必要はない」と
判断した時に、お金がかかるというのが
まったく理解できません。
メーカーサポート期間って一体なんだって感じです。

C++解説7(参照)

1.1 参照とは
ポインタについては理解できたと思います。
しかしC++ではポインタより便利な概念の参照というものが導入されました。
これは非常に有効な機能であるため覚えておくと大変いいでしょう。
参照とは関数側で関数呼び出し元で引数に与えている変数のアドレスを参照する事を宣言します。
まあ、言葉で聞くより1回プログラムを書いてしまうのが
これについては一番いいと思いますので、簡単なswap関数を記述します。

#include "stdio.h"

void c_swap( int *x, int *y ) {
int z;
z = *x;
*x = *y;
*y = z;
}

void cpp_swap( int &x, int &y ) {
int z;
z = x;
x = y;
y = z;
}


int main(void) {
int a, b;
a = 1; b = 2;

printf("a = %d, b = %d\n", a, b );
c_swap( &a, &b );
printf("a = %d, b = %d\n", a, b );
cpp_swap( a, b );
printf("a = %d, b = %d\n", a, b );

return 0;
}

実行結果
a = 1, b = 2 // 代入した値
a = 2, b = 1 // c_swap後
a = 1, b = 2 // cpp_swap後


内容は簡単に理解できると思いますので、参照の文法についてから触れます。
参照とは変数宣言に&を使用します。
ポインタは*に対して、参照は&と記述するだけなので
そんなにここについては抵抗がないと思います。
参照された引数については、実際のアドレスを参照する事になります。
そのため、値を変更すると参照先のアドレスである実際に
引数として設定した値が変更される事になるのです。
また、参照で指定した引数は通常に宣言したものとして同じように使用できるため
「->」(アロー演算子)など必要とせず「.」という演算子でアクセスできます。
これは効率の面からも可読性の面からも大変すぐれた仕組みだと言ってよいでしょう。

関数呼び出しとは一般的にオーバーロードが発生します。
C言語で変更する必要がないためアドレスは渡さないと言った手法が存在します。
その場合、引数すべての値のコピーが発生します。
しかし、アドレス渡しとは参照するためのアドレスを格納する箱4Byte固定となります。
今ではC言語もconst付きで引数をアドレス渡しを行えば、
この事象は防ぐ事はできますが
それでも参照の可読性の高さには到底及びません。

1.2. ポインタから参照へ

ここまで説明してきたように参照とはどこかの変数に成り変る事です。
上では関数の引数について参照を扱ってきましたが、
もちろん通常に参照変数を宣言する事も可能です。

int i = 1;
int &r = i;

こんな感じですね。もちろん「r」を出力すれば「1」が出力される事になります。
この何がいいのかというのがと言う事について考えてみます。

まず何と言っても可読性が違います。
よくプログラムを分かり易くするためにコメントを書くと言った事が言われます。
これについて勿論異論がある訳ではありません。
しかしコメントを書いてプログラムが分かり易くなるでしょうか?
ここはずばり「ノー」と言うしかありません。
コメントを入れて分かり易くなるのは、そこでのコードが何を行おうとしているのかであって
プログラム事態は分かり易くはなりません。
何を行おうとしているのか分かる事によってプログラムを読む手助けになると言う訳です。
プログラムを分かり易く書くというのとは、まったく別次元の話だと思います。
それにこの事を理解しないで以下のようなコメントを見た事があります。

// メモリーを確保する
p = (char*)malloc( 10 );

ふざけてるとしか思えません
これにコメントが必要ですか?
プログラムのコメントを書くという事と解説を書くという事が同じ事になっています。
プログラムを教材として使用する場合にその解説に記述するのであれば
多少は許せますが、自分で書くプログラム、職業として書くプログラムには不必要なコメントです。
少し脱線し過ぎました。

要するに、可読性が高いというのは
人間の目に主観的に捉えやすいという事だと思います。
C++がC言語より可読性が高いのはもちろん参照が全てを決める訳ではありません。
参照なんて、どちらかと言うと大して効果が出ない方の部類でしょう。
それでも、プログラムから「*」や「&」が圧倒的に少なくなる
プログラムを一度見てしまうと全然違います。

参照はめちゃくちゃ意識して書いて下さい。
いつか、それがスタンダードとなって自然に書くようになります。

金曜日, 1月 25, 2008

C++解説6(string型)

今回は一旦文法的な話から離れてC++は便利だって事に説明を割きます。
最初にタイトルになっているstring型とはありません。
stringとはクラスの名前です。
つまり、クラス宣言をしているようなものです。
しかし、ここではstring型と表現します。

文字列を表現する上でC言語というのは非常にダメ言語でした。
何を行うにも、演算子が使えず
strcmp、strcpy、strcat
など様々な関数を使用して処理の実現を行ったきました。

これはC++においても同じで結局プログラミング言語というのは
文字列を扱うのが難しいのでしょう。

それでもいろいろなプログラミング言語は様々な工夫を行って
文字列の扱いを簡単にする努力を行ってきたようです。
C++ではstringがそれにあたります。

stringとはクラスです。
クラスとは一言でいうと型です。

int i;
という文があれば、これは「i」という変数名で「int」型を宣言した事になります。
クラスとは型ですから、
string str;
という文があれば、「str」という変数名で「string」型を宣言したという事です。
準備はこれだけで終わりです。

それではC言語で苦労、又は著しく可読性を下げた
プログラムの簡素化のスタートです。


1.1.文字列比較
char str1[4] = "abc";
char str2[4] = "abc";

if (strcmp(str1, str2) == 0) {
}

C言語では上記のように記述しますが、stringを使用すると以下のようになります。

string str1("abc");
string str2("abc");

if (str1 == str2) {
}

これはどう考えても下の方が良いでしょう。
数値を比較しているかのようです。
どうしてこのような比較ができるのかは
クラス、演算子オーバーロードの2つを理解すれば分かります。
ここでは、上記比較が行えるという事が重要であり
char[]ではなくstringを使用した方が良いという点です。


1.2.文字列複写
文字列比較が「==」という演算子を使用して記述できると
いろいろと試して見たくなる事があるでしょう。
そして、そのほとんどが期待通りに動作すると思います。
string str1("abc");
string str2("def");
char *str3 = "ghi"
char str4[4] = "jkl";

str1 = str2;
str1 = str3;
str1 = str4;
この全てが成立します。
数値型では代入といい、文字列だけ複写という表現を使用すると思います。
同じ事を行うのですから、代入という表現で何も問題がなかったにも関わらず
そこに抵抗があったのは、記述方法に違いがあったからでしょうね。


1.3.文字列連結
連結も何の事はありません。
string str1("abc");
string str2("def");
char *str3 = "ghi"
char str4[4] = "jkl";

str1 += str2;
str1 += str3;
str1 += str4;
特に説明は不要だと思います。


1.4.要素へのアクセス
要素へのアクセスも同じ事です。
char str1[4] = "abc";
string str2("abc");

if (str1[0] == str2[0]) {
cout << "agree" << endl;
} else {
cout << "disagree" << endl;
}

は成立します。
本当に簡単だと思いませんか?
「strxxx」なんて関数は一切使用しなくなってしまいます。
しかも可読性が非常に高い。
C++はここへの拘りが非常に強いと思います。


1.5.検索
文字列からある特定の文字を探したい場合は
C言語ではどのようにするか?

ポインタを取得したい場合は
char *p
char str[] = "abcde";
char c = 'c';
p = strchr(str, c);

要素位置を確認したい場合は
int i;
char str[] = "abcde";
char c = 'c';
for(i = 0; i < strlen(str); ++i) {
if (str[i] == c) {
break;
}
}
とか書くのでしょうね。
下の例はポインタを知りたい場合でも有効ですが、
上の例と比べると見た目が今一です。

これが文字列検索に変わると
「strstr」という関数を使用するようになり
下の例では「strcmp」などを使用して書くことになります。

当たり前の事で何も思わないかもしれませんが
今一な事は常に頭に置いておく事で新しい事への発見ができます。
はっきり言って今一です。
結局、行っているのは「検索」です。
それを何で、何を検索するかで使い分けなくてはいけないのか?
頂けませんね。

上と同じ事を実現する場合のC++の例です。
string str("abcde");
char str1[] = "cd";
char c = 'c';
long l;

l = str.find(c, 0);
l = str.find(str1, 0);
見ただけで何を行っているのかピンと来る事でしょう。
findしているのです。
また、findにはいくつか種類があります。

find_first_of : 前方から検索し、最初に検出された箇所の位置を返します。
find_first_not_of : 前方から検索し、最初に違った箇所の位置を返します。
find_last_of : 後方から検索し、最初に検出された箇所の位置を返します。
find_last_not_of : 後方から検索し、最初に違った箇所の位置を返します。

また、探し方も文字でも文字列でも可能で本当に便利になりました。
細かく理解をしょうとするとここでも覚える事は沢山あります。
でも難しい事は後にして、便利になった箇所を沢山使っていきましょう。
最後に理屈を知っていれば十分です。


1.6.挿入、削除
文字列操作において、良く使用する機能って何なのか?
人によるのでしょうが難しい問題です。
文字列を操作する事よりは文字列を一つのデータとして扱う場合に
非常に扱いづらかっただけで
ここから記述する事に関しては、C言語だけが抱える問題ではない気がします。
様々な言語は容易にする仕組みを考えています。

挿入とは文字列のある位置に別の場所に保存している
文字、文字列を入れる事を指します。
C言語であれば、以下のようなプログラムになるかと思います。
char str1[10] = "abcf";
char str2[] = "de";
char *strInsPos;

strInsPos = strchr(str1, 'c');
strInsPos++;
memmove(strInsPos + strlen(str2), strInsPos, strlen(strInsPos));
memcpy(strInsPos, str2, strlen(str2));
こんな感じでしょうか?
さらに安全に記述すると
if ((strlen(str1) + strlen(str2)) < 10) {
memmove(strInsPos + strlen(str2), strInsPos, strlen(strInsPos));
memcpy(strInsPos, str2, strlen(str2));
} else {
/* 拡張サイズ不足 */
}
要するにメモリ範囲外へのアクセスを未然防止ってロジックが必要になります。


C++のstringを使用するとになると、以下の通りで済みます。
string cppstr("abcf");
char cppstr2[] = "de";
long l;

l = cppstr.find('c', 0);
cppstr.insert(l + 1, cppstr2);
メモリに関するいろいろな処理が無くなっています。
そんな事に苦労する必要がないって事ですね。

反対に削除の場合はどうするかと言うと
string cppstr("abcf");
long l;

l = cppstr.find('c', 0);
cppstr.erase(l + 1);
これは'f'が削除される例です。

この辺りになってくると頻繁に使用するかどうかは微妙なところもありますが
使う場合はこんなにも違うって事ですね。


1.7.文字列トークン分割
私の経験では、それなりに使用する場面がありましたが
一般的にはどうなのか分りません。
csvファイルを解析する際に、必要となる機能です。
C言語ではこれを「strtok」関数で実現していました。
char str[] = "abc,def,hij,klm";
char *tmp;

tmp = strtok(str, ",");
while(tmp != NULL) {
printf("%s\n", tmp);
tmp = strtok(NULL, ",");
}
C++では...
実はこいつが非常にイケてません。
はっきり言って相当するものはありません。
C言語を知っている人であれば、strtokを使用して下さい。
もちろん、これを実現するクラスを作成すれば良いのですが
ここでは見送りです。


と言う事でstringについてはお終いです。
char*より優れている事は分って頂けましたでしょうか?
分かって頂ければ光栄です。

木曜日, 1月 24, 2008

C++解説5(クラスについて2)

1. インスタンス変数/関数とクラス変数/関数

クラスとは型宣言である事は述べました。
しかし、そこはユーザー定義型のためいろいろな事ができるようになっています。
その中の一つにクラス変数とクラス関数というものがあります。

最初にインスタンスという言葉について触れておきましょう。
インスタンスとは「例えば」何て訳を学校で習った覚えがあるのは私だけではないでしょう。
普通、「例えば~」と説明する場合、~には具体的な例などを上げるのだと思います。
何となく近づいてきましたかね。
ここではインスタンスとは実態を指します。
int i;

という宣言文があった場合、iをインスタンスと言います。
classの宣言はintの宣言と言う事になります。
C++において、int,doubleと言った型はクラスではありません。
しかし、C++の仕様においてintと宣言した場合は32bitで表現可能範囲を示すとか、
unsigned intと記述された場合は最初に符号ビットを必要としないため、
intより+範囲に大きく数値を管理できるなど、すべて仕様として決められています。
この仕様を決めるのがクラスの定義となります。しかし、定義だけでは使用できません。
構造体でも定義だけではなく、実態を作成する宣言と言った事が必要となります。
この実態宣言されたものをインスタンスと言います。

class Human {
private:
char *Name;
int Age;
char Birthday[9];
public:
Human(char*, int, char*);
~Human();
};

とクラス定義があった場合に

Human obj1;
Human obj2;
と宣言されると、obj1のName,Age,Birthdayとobj2のName,Age,Birthdayは
全く別のものになります。もちろん、Human()も~Human()も同様です。
これらをインスタンス変数、インスタンス関数と表現します。

では一体、クラス変数、クラス関数とは何でしょうか?
これはインスタンスのものではなく、クラスのものという事になります。
C++ではこのような変数又は関数をstaticを付けて表現します。
たとえば、世の中の人口を管理すると仮定します。
そんな値を管理するのは何処が適しているでしょうか?
いろいろと分析方法は異なるため、何処が一番適しているという答えはありません。
しかし一つの答えに人間の事は全部人間のクラスで管理しろ!という考え方があっても良いでしょう。
ここではそれをクラス定義に盛り込み、実際に使用してます。

--------------------------------------------------------------------------------
class Human {
private:
static int HumanCount; // クラス変数
static void HumanCountAdd(); // クラス関数非公開
static void HumanCountSubtract(); // クラス関数非公開

char *Name;
int Age;
char Birthday[9];
public:
Human(char*, int, char*);
~Human();

static void HumanCountPrint(char*); // クラス関数公開
};

int Human::HumanCount = 0;

void Human::HumanCountAdd() {
HumanCount++;
}

void Human::HumanCountSubtract() {
HumanCount--;
}

void Human::HumanCountPrint(char* Title) {
std::cout << Title << ":HumanCount = " << HumanCount << "\n";
}

Human::Human(char *InName, int InAge, char *InBirthday) {
Name = new char(strlen(InName));
strcpy(Name, InName);
Age = InAge;
strcpy(Birthday, InBirthday);
// std::cout << "(" << Name << ") Human::Human()\n"; // ←今回は削除
Human::HumanCountAdd(); // ここにカウントアップを追加
}

Human::~Human() {
// std::cout << "(" << Name << ") Human::~Human()\n"; // ←今回は削除
delete Name;
Human::HumanCountSubtract(); // ここにカウントダウンを追加
}

int main(void) {
Human::HumanCountPrint("no create"); // この関数で現在の数をプリントします

Human obj1("semona", 0, "20040101");

Human::HumanCountPrint("obj1 create");

Human *obj2 = new Human("yuuna", 1, "20030101");

Human::HumanCountPrint("obj2 create");

delete obj2;

Human::HumanCountPrint("obj2 delete");
}
-------------------------------------------------------------------------------
実行結果
-------------------------------------------------------------------------------
no create:HumanCount = 0
obj1 create:HumanCount = 1
obj2 create:HumanCount = 2
obj2 delete:HumanCount = 1
-------------------------------------------------------------------------------
という結果が得られます
「う~ん全部なくなってるはずなのに0にならない」という問題はありますが
クラス変数、関数については理解できたと思います。
ちなみに、「HumanCountPrint」をprivate宣言に変えると、コンパイルエラーが出ます。
クラス関数を非公開にすると言う事は当クラスのインスタンス外からのアクセスを禁止する
と言う事になります。変数についても同様です。
という説明をするために、「HumanCountPrint」を公開関数にしたんですけどね。

最後はかっこよく0にしたいから、「HumanCountPrint」をコンストラクタ又はデストラクタで呼び出すように変更してみます。
--------------------------------------------------------------------------------

#include "iostream"
#include "cstring"
#include "cstdio"

class Human {
private:
static int HumanCount;
static void HumanCountAdd();
static void HumanCountSubtract();
static void HumanCountPrint(char*);

char *Name;
int Age;
char Birthday[9];
public:
Human(char*, int, char*);
~Human();

};

int Human::HumanCount = 0;

void Human::HumanCountAdd() {
HumanCount++;
}

void Human::HumanCountSubtract() {
HumanCount--;
}

void Human::HumanCountPrint(char* Title) {
std::cout << Title << ":HumanCount = " << HumanCount << "\n";
}

Human::Human(char *InName, int InAge, char *InBirthday) {
Name = new char(strlen(InName));
strcpy(Name, InName);
Age = InAge;
strcpy(Birthday, InBirthday);
// std::cout << "(" << Name << ") Human::Human()\n"; // ←今回は削除
Human::HumanCountAdd(); // ここにカウントアップを追加

char str[32];
memset(str, 0, 32);
std::sprintf(str, "%s create", Name);
Human::HumanCountPrint(str);
}

Human::~Human() {
// std::cout << "(" << Name << ") Human::~Human()\n"; // ←今回は削除
char str[32];
memset(str, 0, 32);
std::sprintf(str, "%s delete", Name);
delete Name;
Human::HumanCountSubtract(); // ここにカウントダウンを追加

Human::HumanCountPrint(str);
}

int main(void) {
Human obj1("semona", 0, "20040101");
Human *obj2 = new Human("yuuna", 1, "20030101");

delete obj2;
return 0;
}

-------------------------------------------------------------------------------
実行結果
-------------------------------------------------------------------------------
semona create:HumanCount = 1
yuuna create:HumanCount = 2
yuuna delete:HumanCount = 1
semona delete:HumanCount = 0
--------------------------------------------------------------------------------
と言う事になります。

火曜日, 1月 22, 2008

C++解説4(クラスについて)

今回はオブジェクト指向と言われるもので
このクラス表現と言われるものがかなりの比重を占めています。
一言で言ってしまうとクラスとは構造体に関数を持たせたものです。
もちろん、それだけではない、様々な機能を提供してくれます。
クラスの文法は構造体と基本的に変わりません。

struct 構造体名 {};
に対して
class クラス名 {};
という感じです。

アクセス修飾子のpublic,protected,privateというものがありますが
順々に覚えていけばいいので、はじめは無視してしまいましょう。

class CHuman {
};

終わりです。もちろんこれだけでは何も使用できません。
そこで、名前と年齢という変数を持たせてみると

class CHuman {
char *strName;
int nAge;
};

#include "stdlib"
#include "string"

int main(void) {
CHuman obj;
char *Name = "名前";
obj.strName = (char*)malloc( strlen(Name) + 1 );
strcpy( obj.strName, Name );
obj.nAge = 20;
return 0;
}

となります。まあ、これだけであればクラスなんてものは必要ありません。
構造体と何も変わらないからです。
まあ、構造体の場合はtypedefしないと「struct 構造体名 変数名」としていた箇所を、
クラスの場合はtypedefしなくても
「クラス名 変数名」記述すれば良い分少しだけ良くなったかも!
何て言ったところで覚える価値はありませんね。
それではどんどん拡張して覚える価値のあるものにして行きましょう。

まず最初にアクセス修飾子に触れてみます。

class CHuman {
public:
char *strName;
int nAge;
};

と記述してみます。
先ほど、記述したメインと合わせてコンパイルすると何も変化がありません。
そうです。何もありません。

class CHuman {
private:
char *strName;
int nAge;
};

次にpublicと記述した箇所をprivateと変更してみましょう。
コンパイルエラーとなってしまいました。
privateとはずばり、クラス外には見えなくする修飾子となります。
それに対して、publicとは見えるようにする修飾子です。
つまり、もともと省略していたためpublicと解釈されていただけだったのです。
ビックリしました? まあ、ビックリしませんね。
protectedに付いては、継承のところで説明します。今はこの2つで十分です。

ところで何のために必要なの?
なんて考えてしまった人のために少しだけ補足しましょう。
今回は人間をクラスとして考えていますのでこれを例に取ります。
C言語の構造体の考え方は人間に関係する変数を
一括管理できる事がすばらしい事でした。
しかし、よ~く考えてみると人の年齢を誰が上げたのかが(更新した)
構造体ではまったく分かりません。
もっと言うと、そもそも人の年齢って下がるものなのでしょうか?
現実世界で考えると、人の年齢は誕生日が来る事によって上がる事になります。
これは、不変な事で毎日年を取るとか何て事があると困ってしまいますね。
長寿記録などあっさり更新ですね。
このように、誰でも変更できたものをそうではなくした事が重要なんです。
でもどうやって変更するの?っと思ったら少し考えれば解決です。
なぜなら、publicと修飾されていた時は、誰でも変更できました。
これは、publicで修飾されたものは公開アクセスだったからですね。
公開アクセスとは、誰でも参照できますよって事です。
たっだらいっその事変更する関数をpublicに置けばいいんじゃないの!
何て考えが浮かべばいいですね。
一番最初にクラス説明した時に、
「一言で言ってしまうとクラスとは構造体に関数を持たせたものです。」って
ところがありました。構造体では事ですね。
※実際には関数ポインタなどを駆使して近いものを作成する事ができます

class CHuman {
private:
char *strName;
int nAge;
public:
void UpdateAge(void) {
nAge++;
}
};

こんな感じで書いておけば良いです。年をとる事しかできません。
でも、誰でも変更できるじゃん!と思うかもしれませんが
さっきと決定的に違うのは、変更された時が分かるという事です。
N歳になったら何かあるのであれば、これは問題なく対応可能と言う事です。
ちなみに、privateのような修飾子で変数の内容を隠す事ができます。
このようにする事を一般的に情報隠蔽、カプセル化などど表現します。

で簡単に文法を説明しておきますと

//
// クラス記述方法
//
class クラス名 {
private:
// ここに非公開変数、関数を記述する
// 関数は基本的に宣言のみ。簡単なコードが記述可能
// inlineのからみがあって、複雑なのは書けません
// いずれ機会を作って、inline関数については説明します
public:
// ここに公開変数、関数を記述する
// 関数については、private同様簡単なものだけです
};

//
// クラスメソッド(関数)記述方法
//
返却値 クラス名::関数名() {
// 関数の内容を記述
}

簡単ですが、こんな感じです。


クラスはコンストラクタで初期化を行い、デストラクタで後処理を行います。
クラスとは簡単に言ってしまえば型の定義です。
つまり、プリミティブ型としてlong,doubleなどが用意されているにも関わらず
そんな型じゃ話にならん!!ってな状況ってありますよね。
言ってしまえば、C言語であった構造体だって
型の定義じゃないですかてな話ですよ。
でもC言語の構造体っていろいろと問題があったわけですよ。

たとえば、説明しましたが構造体はすべての構造体の中の変数がグローバルですよね。
これって以外と使えね~って思いませんか。

「構造体の初期化ってどうやってたの?」
「構造体を破棄するときって、何もしなくていいの?」
などなど...
(ここがコンストラクタとデストラクタの説明箇所だから強調させて下さい)

たとえば、平面のポイントを表す構造体を宣言すると

struct Point {
int x_;
int y_;
};

struct Point p;

でその後に、実際今宣言したポイントは何処なのかってな話で

p.x_ = 1;
p.y_ = 1;

って書いていましたですよ! でもこれっておかしくね~~~。
だって宣言する時にはもうポイントが何処かなんて分かっているんですよ!!
だったら、宣言時に初期化させて下さいよ。

すると以下のように書き直します。
struct Point p = { 1, 1 };

でも以下の場合はどうでしょうか?

struct Point {
int x_;
int y_;
};

struct Human {
char Name[12 + 1];
int Age;
struct Point *p;
};

こいつは先ほどの流れで書くと

struct Human h;

strcpy( h.Name, "name" );
h.Age = 20;
h.p = ?????; // あれ、これって先に宣言しておかなければ駄目じゃん

となって

struct Point p = { 1, 1 };
struct Human h = { "name", 20, &p } ;

ってな感じになりますかね。
でもって何が言いたいかと言いますとそもそも構造体を作成する時に
「必要な情報を構造体とは別に私どもが情報を管理するなどど言う事はナンセンスだ!!」
と言う事ですよ。
上の例で言えば、人を作成するまでは、(「struct Human h」の箇所)
何処に人がいるかなどど言う事はまったく関係ない!(「struct Point p」の箇所)
人をあるポイントに作成するのであって、ポイントと人を作って結びつけるなどはあんたがやってくれって感じですよ。
さらに、人が死んだ(消滅した)時に何だってポイントを私どもが消さなくてはならないのですか?
そんなの人が死ぬ時に責任持って消してくれって感じですよ!(2回目)

そんなあなたの要望に答えてくれるものは
コンストラクタでありデストラクタなんですよ。

でコンストラクタから説明します。
ずばり、コンストラクタとはクラス(構造体)の初期化です。
というかその前に、C++においてクラスと構造体の違いを説明しておきましょう。

ずばり、違いはありません。
本当は少しだけあるのですが、無いと言って問題ありません。

class Point {
int x_;
int y_;
public:
int getPosX(void);
int getPosY(void);
};
と書いている人がいたら、思いっきり違いがあります。
なぜなら、構造体はデフォルトがpublicなんです。だから
struct Point {
int x_;
int y_;
public:
int getPosX(void);
int getPosY(void);
};
なんて書こうものなら、すべてpublicと言う事になります。

つまり、クラスを
class Point {
private:
int x_;
int y_;
public:
int getPosX(void);
int getPosY(void);
};
と書いていれば、classをstructに変えても何も違いはありません。
と言う事で極力、デフォルトを使用せずに明記するようにしましょう。
でも、C++ではstructと記述はあまりしませんね。
C言語の構造体のようなものを定義する必要性がある時に
structと記述するのが良いと思います。(定番ですかね)
でもそんな時ってないと思います。

で話を戻してコンストラクタですが初期化です。
この 「= 1」に相当します。
またまた少し挫折します。

// 初期化
int i = 1;

// 代入
i = 1;

C言語において上の例を初期化といい、下の例を代入と言います。
はっきり言って、最終的な結果は何も変わりません。
しかし、代入の「i = 1」の前に「if ( i == 1 )」何て挿入しようものなら
iの値は不定です。
代入と初期化の一番大きい違いは、代入は邪魔できるけど初期化はできないって事です。
そして、コンストラクタとはクラスの初期化です。
つまり、クラス変数を定義した時にはコンストラクタとは常に実行され
定義直後に参照したところで、コンストラクタとの間には入れないって事になります。
コンストラクタ有りのクラスを作成してみます。

class Human {
public:
Human();
};

このように、クラスと同じ名前を持つメソッド(関数)となります。
返却型はありません。何も返却しないからです。
このコンストラクタという関数の中にクラスの初期化処理を記述します。

少し上のクラスを拡張します。

class Human {
private:
char Name[12];
int Age;
char Birthday[9];
public:
Human();
};

このようなprivate変数を管理している場合、コンストラクタでprivate変数を
初期化してしまうのが最もポピュラーな使用方法となるでしょう。

Human::Human() {
strcpy( Name, "NameValue");
Age = 0;
strcpy( Birthday, "20000101" );
}

てな感じです。
う~ん、でもこれではあんまり使えないコンストラクタですね。
名前も、年齢も、誕生日も固定なんて!!
その場合は、コンストラクタに引数として貰えば良いだけです。

public:
Human( char*, int, char* );

何て宣言方法に変わって、そんでもって
Human::Human( char *InName, int InAge, char *InBirthday ) {
strcpy( Name, InName );
Age = InAge;
strcpy( Birthday, InBirthday );
}

ちなみに、引数のまったく持たないコンストラクタを
一般的にデフォルトコンストラクタと言います。
覚えておきましょう!

次はデストラクタです。
これは初期化に対して終了処理、後処理という言い方が正しいと思います。
つまり、クラスを破棄する時にただ破棄して問題がある場合に
ここで後処理を行うという事になります。
たとえば、上のクラスでは名前がName[12]という形式で宣言していました。
しかし、名前なんてどのくらいの長さなのかは分かりません。
そこで、名前はchar*という形式に置き換え、
コンストラクタで指定されたサイズを格納できるように設定するように変更します。

class Human {
private:
char *Name;
int Age;
char Birthday[9];
public:
Human( char*, int, char* );
~Human();
};

Human::Human( char *InName, int InAge, char *InBirthday ) {
Name = new char(strlen(InName));
strcpy( Name, InName );
Age = InAge;
strcpy( Birthday, InBirthday );
}

Human::~Human() {
delete Name;
}

このようにすると単純にクラスを破棄した場合、Nameはメモリーリークする事になります。
そこでデストラクタの登場という訳です。
このデストラクタによってメモリーリークを防ぐという事になります。
それでは実際にprint分を入れて実験してみましょう。

#include "iostream"
#include "cstring"

class Human {
private:
char *Name;
int Age;
char Birthday[9];
public:
Human( char*, int, char* );
~Human();
};

Human::Human( char *InName, int InAge, char *InBirthday ) {
Name = new char(strlen(InName));
strcpy( Name, InName );
Age = InAge;
strcpy( Birthday, InBirthday );
std::cout << "(" << Name << ") Human::Human()\n";
}

Human::~Human() {
std::cout << "(" << Name << ") Human::~Human()\n";
delete Name;
}

int main(void) {
Human obj1( "semona", 0, "20040101" );
Human *obj2 = new Human( "yuuna", 1, "20030101" );

delete obj2;
}

--------------------------------------------------------------------------------
実行結果
--------------------------------------------------------------------------------
(semona) Human::Human() // Human obj1( "semona", 0, "20040101" );
(yuuna) Human::Human() // Human *obj2 = new Human( "yuuna", 1, "20030101" );
(yuuna) Human::~Human() // delete obj2;
(semona) Human::~Human() // }
--------------------------------------------------------------------------------
特に解説は不要だと思いますが、
実行結果の後ろに付けたコメントは実際に
何処で動作しているかのポイントを示しています。
クラスをポインタで定義したobj2はnewでコンストラクタ、
deleteでデストラクタがobj1は宣言時にコンストラクタ、
そしてそれがスコープ外となった時にデストラクタがそれぞれ動いています。

月曜日, 1月 21, 2008

土曜日の的中でプラスに転じた

今週は、土曜日の中山11R、京都11R、12R
日曜日の中山11R、京都10R、11Rと合計6Rの購入でした。
的中は土曜日の中山11Rと京都12Rで今年の収支がプラスになりました。

惜しい事をしたのは、中山10Rのコンラッドと中山11Rのマイネルチャールズの2頭で
単勝馬券か馬連かで迷い馬連を選択。
相手不明の10Rは購入を見送り。
マイネルチャールズの相手も不明だったのですが
購入しないのも寂しいので、唯一の牝馬リトルアマポーラを指名。
馬連1点の勝負でしたが、残念ながら...
幸四郎君の追い出しが遅かったんではないか?とか思ったりしました。
もしかしたら馬がずぶかったのかもしれないけど...
見ていたら、ここだってところで行かずに後で追い上げるも
勝負は決した後って感じに見えました。残念です。

京都11Rは3週連続というところが気になったところではあったのですが
つまらない予想で岩田さんのアドマイヤジュピタから、ヒラボクロイヤルを相手に指名。
まったく的外れな予想となり、くやしくも何ともない大負けです。

負け分も何とか取り戻したため、来週のAJCCから再スタートですね。

C++解説3(ポインタの確認)

C言語を勉強している多くの人がポインタで挫折するようですね。
何でポインタが難しいのか考えてみます。

int i;
このような変数宣言があるとiはint型の変数である事が宣言されています。
int型とは一般には32bitで構成される数値を管理する型となりますよね。

ポインタもこれとまったく同じ考え方です。
int *p;
このような変数宣言があるとpはint*型の変数である事が宣言されています。
int*型とは32Bitで構成されるアドレスを管理する型となります。

でも宣言は基本的にこれですべてです。
整理して考えれば難しい話は一つもありません。

void swap( int *p, int *q ) {
  int s;
  s = *p;
  *p = *q;
  *q = s;
}

上の関数は入れ替え(swap)を行っていますよね。
ポインタを使っていますが、多分これを難しいと思う人はいないと思います。
簡単に説明するとC/C++において「*」は演算の意味を持っています。
int型に*と書かれていれば、相手ありきとなりますが掛け算となります。
intポインタ型に*と書かれていれば、そのアドレスが指す値と言う事になります。
そのため、上のswap関数は引数としてもらったアドレスが指す要素の値を
書き換える事ができているのです。
つまり、C言語ではアドレスを渡さないと呼び出された関数側では
値を書き換える事ができないという事になります。
関数で引数として宣言している変数は、呼び出し元とは別の領域が確保されます。
関数側ではその値を書き換える事になります。
よって関数側にアドレスを渡し、引数として受け取った関数は
そのアドレスが指す値を変更する事で値の変更を行えるのです。


もう一つ重要な話にC言語において配列はポインタとなるという話があります。

int i;
この宣言がスタック領域に詰まれると以下のようになるとします

「iの領域」
ここにintで宣言されていれば32Bit格納できる大きさで領域が確保されます。
0 = 00000000 00000000 00000000 00000000
1 = 00000000 00000000 00000000 00000001
ってな感じになりますね。

int array[4];
この宣言が行われれば当然intの箱を4つ作れと宣言されているので
32Bit格納できる大きさの領域を4つ分確保します。
つまり上の「iの領域」が連続して4つ確保される事になります。

ここで問題があります。
「i」と宣言したものは当然「i = 0;」と書かれれば
「i」の領域に代入すればいいのですが
「array = 0;」と書かれた場合は
何処に代入すればいいのか分からないという事になります。
そこで代入する時には修飾子として「array[0] = 0;」
といった感じでindexを指定します。
では「array」とは何を指しているのでしょうか?
C言語では配列の変数名は先頭のアドレスを指している事になっています。
つまり「array == &array[0]」という事になります。

では実際に配列を関数に渡してみます。

#include "stdio.h"

void PrintArray( int *Array, int ArraySize ) {
  int i;
  for( i = 0; i < ArraySize; ++i ) {
    printf("%d,", Array[i] );
  }
}

int main(void) {
  int i, Size, Array[10];

  Size = 10;
  for( i = 0; i < Size; ++i ) {
    Array[i] = i;
  }
  PrintArray( Array, Size );

  return 0;
}

実行結果
0,1,2,3,4,5,6,7,8,9,


同様に文字列を関数で出力してみます

#include "stdio.h"

void PrintArray( char **Array, int ArraySize ) {
  int i;
  for( i = 0; i < ArraySize; ++i ) {
    printf( "%s,", Array[i] );
  }
}

int main(void) {
  int Size;
  char *Array[2] = { "senna", "yuuna" };

  Size = 2;
  PrintArray( Array, Size );

  return 0;
}

実行結果
senna,yuuna,

intの配列と何も変わりませんね。
配列はポインタとなるところはそのままなので、
ポインタの配列でポインタのポインタと
なってダブルポインタという事になります。
特に難しい話ではないと思います。

このダブルポインタというものは混乱する人も多いようですが
C言語は文字列はcharの配列になる。
charの配列と言えば、配列なのでポインタとなる。
ポインタの配列と言えば、ポインタのポインタとなる。
何て順序立てて考えれば、難しい事はないと思います。

文字列の配列を関数に渡す事に成功しました。
と言う事は多次元配列(文字列はcharの配列のため)について渡す事に
成功したという事になります。
であれば、int _2DArray[10][10];で宣言されている配列を渡す事も問題なく
理解できると思います。何ていっときながら失敗しちゃうんですよ!
多分、上記の流れでは以下のプログラムをイメージする事でしょう。

#include "stdio.h"

void PrintArray( int **Array, int _1DArraySize, int _2DArraySize ) {
  int i, j;
  for( i = 0; i < _1DArraySize; ++i ) {
    for( j = 0; j < _2DArraySize; ++j ) {
    printf( "%s,", Array[i][j] );
   }
  }
}

int main(void) {
  int _1DSize, _2DSize;
  int Array[3][3] = { 1, 2, 3, 4, 5, 6 };

  _1DSize = _2DSize = 3;
  PrintArray( Array, _1DSize, _2DSize );

  return 0;
}

コンパイルエラーという結果がでたと思います。
2次元配列は文字列の配列とは異なって、同じような引渡しができません。
このような配列を引数として渡す場合、配列数を解決しておく必要があります。
配列とはポインタになる事は問題ないと思いますが、
2次元配列だからダブルポインタという考え方が間違っている事になります。
配列は2次元だろうが、3次元だろうがポインタです。
もちろん、intポインタを格納する配列を作成する事も可能です。
intポインタとは配列を指すため(まあ配列とは限りませんが)
ポインタの配列となり、先ほどの文字列の配列と同じ扱いになります。
それでは、実際にコンパイルエラーとなったプログラムを
コンパイルエラーとならない状態に修正して実行しましょう。

#include "stdio.h"

void PrintArray( int Array[3][3] ) {
  int i, j;
  for( i = 0; i < 3; ++i ) {
    for( j = 0; j < 3; ++j ) {
      printf( "%d,", Array[i][j] );
    }
  }
}

int main(void) {
  int Array[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  PrintArray( Array );
  return 0;
}

実行結果
1,2,3,4,5,6,7,8,9,


最後にintポインタの配列を格納するプログラムを書いてみます。

#include "stdio.h"

void PrintArray( int **Array, int _1Size, int _2Size, int _3Size ) {
  int i, j, ArraySize[3];

  ArraySize[0] = _1Size;
  ArraySize[1] = _2Size;
  ArraySize[2] = _3Size;

  for( i = 0; i < 3; ++i ) {
    for( j = 0; j < ArraySize[i]; ++j ) {
      printf( "%d,", Array[i][j] );
    }
  }
}

int main(void) {
  int *Array[3];
  int Array0[3] = { 1, 2, 3 };
  int Array1[4] = { 4, 5, 6, 7 };
  int Array2[5] = { 8, 9, 10, 11, 12 };
  int _1Size, _2Size, _3Size;
  _1Size = 3;
  _2Size = 4;
  _3Size = 5;

  Array[0] = Array0;
  Array[1] = Array1;
  Array[2] = Array2;

  PrintArray( Array, _1Size, _2Size, _3Size );

  return 0;
}

実行結果
1,2,3,4,5,6,7,8,9,10,11,12,