Version 6.11
三項演算子
「さて、今回は二項演算子の残りと三項演算子について紹介します」
『三項演算子? 想像付かない……』
「その前に二項演算子の残りを片付けとこ。まずは〈 , 〉、〈カンマ〉か
ら」
『関数の引数区切るのに使うくらい?』
「あと変数をいっぺんにいくつも作るときとか」
void CDebugDlg::OnButton1()
{
int i1 = 100, i2 = 200;
TRACE( "%d, %d\n", i1, i2 );
// 100, 200
}
『こうすれば int 型の変数をまとめていっぱい作れるってことね』
「でもこれって見にくいと思うんだけどね」
『ちょっとね、 i2 が見にくいかも』
「メリットは行が少なくできるくらいしかないから、あんまりこの使い方は
しないほうがいいかも。次は :: 」
『名前空間とかのだよね』
「名前空間は Ver 4.01 ( No.051 ) で教えたね。他にも
CDebugDlg::OnButton1() みたいにクラス名とメンバ関数をくっつけるとき
にも」
『でもさ、メンバ関数呼ぶ時って普通 . 使うじゃない』
「そう、メンバ関数やメンバ変数にアクセスする時には、 . や -> の演算
子を使います」
『普通は . で、ポインタの時は -> を使うんだよね。この使い分けは分か
るんだけど』
「それは Ver 6.02 ( No.102 ) でしっかり教えたものね。 :: か . かは、
簡単に言うと :: の左オペランドが色々変わるなら . や -> 、変わらない
なら :: 、ってとこ」
『?』
「たとえば、今開いてる DebugDlg.cpp にこういうのあるでしょ」
void CDebugDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
// 略。
CAboutDlg dlgAbout;
dlgAbout.DoModal(); // ここ。
// 略。
}
『〈なんとかについて〉のダイアログを表示するとこだよね』
「ここで呼んでる CDialog のメンバ関数 DoModal() 。これの . の左側の
dlgAbout は、メモリ上のどっかに作られてる変数でしょ」
『あ、どこに作られるか分かんない、それが〈色々変わる〉ってこと?』
「そゆこと。 dlgAbout の中に入ってるダイアログのウィンドウハンドルも
毎回毎回変わるしね」
『そういうときは . を使うんだ』
「 :: を使うのは、変わらないって場合。たとえば、今火美ちゃんにしてる
ように CDialog::DoModal() を説明する時、 DoModal() って感じにメンバ
関数だけ書くと分からないからクラス名を付けたい、そのクラス名は変数み
たく中身やアドレスとは関係ない」
『だから CDialog::DoModal() ってするんだ』
「名前空間も変数と関係ないから :: ね」
『でもさ、前に :: を変数っぽいのに使ったことあるけど』
「 CFile::modeRead とかだね。 Ver 5.13 ( No.078 ) でも触れたけど、こ
れは enum を使ったただの定数だから、たとえば dlgAbout とかのアドレス
や中身とかに関係ないでしょ」
『だから :: なんだ。でも . でもいいんだね』
「 dlg.About の値ってのも間違いじゃないしね。ま、これはこんなところ
で。 . と -> に似たのに .* と ->* があります」
『な、なんか謎……』
「っつーか、これはかなり難しいから今回はパス。下手に使うと痛い目見る
し」
『げ、そんなにヤバイのなの?』
「たぶん。次は [] 」
『あら、配列の。でもこれって二項演算子?』
「 L[R] なら L が左オペランドで R が右オペランドね」
『これは普通に配列やポインタに使う他に、使い道ないよね』
「ないよ。 Ver 4.11 ( No.061 ) でかなりしっかり方教えたから大丈夫だ
よね」
『ようするにアドレス指定するだけだよね』
「で、これに似たのが () 」
『キャストに使うの?』
「 [] に似たのって言ったでしょ。これは関数呼ぶのに使うの」
『へ? CDialog::DoModal() の () なの?』
「そなの」
『ふーん。これも関数呼ぶだけの機能?』
「そ。正確に言えば微妙に違うんだけど、その話はもうちょっとあとで。
あ、そういえばキャストに使う () も二項演算子だ」
『そなの?』
「 (int)ch だったら、 int が左オペランドで ch が右オペランドね」
『 () がどっちにも使えるんなら、この前言ってた & が単項か二項かって
のと同じに、ちゃんとどっちかに決まるようになってるんだよね』
「ってゆーか関数呼び出しに使う方には型名は入れられないでしょ」
『あ、そっか、変数や定数だけだもんね。それは大丈夫なのね』
「キャストの話が出たところで、キャストに使う、しかも演算子っぽくない
演算子について。 const_cast dynamic_cast reinterpret_cast static_cast
の4つ」
『 reinterpret_cast だけ知ってる。ポインタを int にキャストしたとき
に使ったけど』
「 Ver 4.11 ( No.061 ) とかで紹介したね」
『そんとき言ってたけど、普通のキャストよりもこれ使った方がいいんだよ
ね』
「 () のキャストはどんなキャストでも使えるからちょっと危なっかしいか
らね。 reinterpret_cast ならポインタだけ、だから安全」
『でもポインタだけじゃ不便じゃない? あ! それが!』
「そう、そのために他の3つのキャストがあるんです。まず const_cast は
const 関係のキャスト」
void CDebugDlg::OnButton1()
{
const int i = 100;
int *pi = const_cast< int * >( &i );
*pi = 200;
TRACE( "%d\n", *pi );
// 200
}
『えーっと……?』
「 Ver 4.12 ( No.062 )で const のポインタってやったでしょ」
『んーと……あ、そのページ見ると const int * は int * には入れられな
いはずなのに、これだと入れられてるよね。 &i はアドレスだから
const int * だし』
「そう、そのための const_cast 」
『っつーかそしたら const の意味ないじゃん。 const なはずの i の中身
がちゃっかり書き変わってるし』
「そう、これは最後の手段ってとこ。だから const_cast を使うってことか
な」
『どゆこと?』
「普通のキャストだと間違ってこの const を剥がすキャストをしちゃうか
もしれないけど、この種のキャストならそういうことないし」
『他の reinterpret_cast とかだと const を剥がせないから間違えること
がない、ってことね』
「そゆこと」
『あと、見やすいってのもあるんでしょ? () だとそういう危険なことし
てるように見えないけど、これなら、ね』
「そう、それも重要だね。次、 static_cast は const やポインタとかと関
係ない、普通の数値キャストに使うもの」
『数値キャスト?』
「 char を int にキャストするのとか」
『あー。 dynamic_cast は?』
「それは今回はパス。これもキャストに使うんだけど、もっといろんな知識
がないと使い道分からないのだから」
『っつーか、まだまだ難しいこと多すぎ……』
「難しくはないんだけど、いっぺんに教えるのはまずいから。キャストの他
には、 sizeof も記号じゃない演算子だね」
『これは変数とかのサイズを調べるのだね』
「そだね。これはその使い道しかないから。似たのに typeid があります。
これは、変数が何の型かっていうのを調べる時に使うもの」
『へー……って、それ意味ないじゃん。変数の型なんて初めから分かってる
んだから』
「ところがそうじゃない……んだけど、これもさっきの dynamic_cast と同
じく、難しい話になっちゃうから今回はパス」
『同じ関係なの?』
「そう。火美ちゃんも〈オブジェクト指向プログラミング〉って聞いたこと
あるでしょ?」
『本や Web にいっぱい書いてあるね。でも読んだとき、難しそうじゃない
なーって思ったけど?』
「難しいんだ、これが。だからあとでじっくりとね。最後の二項演算子は、
new delete delete[] 」
『あ、前に見たことある。確か変数を作ったり消したりするのだよね』
「そう。 new で作って delete で消します。 delete[] は、配列として
new したのを消す時に使います。これも難しいから」
『パスぅ!? なんかそればっかし』
「その代わり、あとでイヤってほどしっかり教えるから。中途半端に教わっ
ても使いこなせないよ?」
『まー、ぱぱっと教えてもらってたらポインタとか分かんなかったとは思う
けどさ』
「さて!」
『そうそうそう! 三項演算子のこと教えてよ』
「三項演算子はその名の通りオペランドをみっつ取る演算子。演算子として
は ? と : のふたつを組み合わせて使います。 MSDN の【条件演算子】
−【条件演算子を使った式】を見て」
『日本語だと条件演算子ってゆーのね。……見ても分かんないんですけど』
「相変わらず分かりにくく書いてあるね……。じゃあ、サンプルコード見て
もらおうか」
void CDebugDlg::OnButton1()
{
int iFlag = 0;
int i = iFlag ? 100 : 200;
TRACE( "%d\n", i );
// 200
}
『中の2行目で使ってるね』
「 ? : は、 A ? B : C って感じに使います」
『 A に B に C 、だから三項演算子ね』
「三項演算子は、まず A を if みたくチェックします」
『 0 以外か 0 か、ってヤツ?』
「そうそれ。で、もし 0 以外なら A ? B : C が B に、 0 なら
A ? B : C が C に置き換わります」
『ってことは、上の例だと、 iFlag が 0 だから : の右っ側の 200 に置き
換わるから int i = 200; 、なるほど』
「もし iFlag が 0 以外だったら i に 100 が入るわけ。まー、実際に使う
ときは iFlag のとこに == とか使ったのを入れるけどね」
『それで、合ってたら 100 、間違ってたら 200 とかなるわけだ。って、な
んか if にかなり似てるね』
「うん、基本的に if の代わり。 if を使って値を代入する場合とかに、こ
れでもできるってとこかな」
『じゃーわざわざこれ使う必要ないじゃん』
「うん、だから普通は使わないんじゃないかなぁ。一応、 if よりもすっき
りするってメリットはあるけど」
『読みづらくなるからダメ、じゃない?』
「そゆこと。僕的には普通に if 使う方を勧めます」
/*
Preview Next Story!
*/
『演算子のはこれで終わり?』
「ようやくね」
『ってことは、次回からバグの話に戻る?』
「もちろん。というわけで次回」
< Version 6.12 演算子を気に掛ける! >
『につづく!』
「演算子はバグの温床、憶えること多いから注意してねー」
『う”』