teppyプライベートは大切にしたいほうです。このアーティクルを書いている今、個人的な話ですが仕事がデスマーチでプライベートなんてありません。普段なら、この時期はプライベートジェットでサイパンに飛んで、プライベートビーチに寝転がってiPadでプライベートライアンを見ているはずです。自分のプライベートが守られない今、他人のクラスのプライベートも守りません。積極的に攻めていくスタイルです。仕事の時間};雇われサラリーマンにも生活があります。仕事の時間の他に自分の時間も必要なのです。その部分というのは完全にプライベートなのです。この従業員クラスをもうすこし価値のあるものにしてみましょう。std::endl;}};挨拶できるようになりました。挨拶する対象の職位に応じて挨拶を変えられます。std::endl;}社長の時だけは休暇をせがむようテンプレートを特殊化しました。please.では外部から、このEmployerのprivateメンバにアクセスしてゲームの時間をごっそり仕事の時間に移すことは可能でしょうか。アクセス指定子の無効化というアーティクルの中で、privateメンバにもアクセスする術について記載しました。あれはC++の言語ルール的にはまったくの違法行為です。privateというc++のキーワードを再定義してはいけません。合法的にやってみましょう。10メンバにテンプレート関数があると、外部でその関数の特殊化を行うことができます。これを利用して本来不可侵だったはずのprivateメンバの内容を意のままに書き換えました。アクセス指定子の無効化と違い、今回のアプローチは合法です。特殊化したメンバ関数は、まったく議論の余地がない正式なクラスのメンバ関数ですのでc++の言語ルールに一切抵触していません。この男は言語ルールの抜け道を知っている法律家だ。彼が捕まることは絶対にない。アクセス制御の使用と誤用このアプローチが法に触れそうになる瞬間、それは特殊化に使用した型が既に別の箇所で同様の特殊化に使われており、結果この関数定義がODRに違反する場合です。それも無名ネームスペースに定義したオリジナルの型を用いることにより簡単に回避することができます。teppyC++が他の数多ある言語と一線を画している特徴的な機能の一つにテンプレートという機構があります。......と、書くと一部のクラスタから猛烈な抗議のメールを受け取ることになるので気をつけましょう。彼らはHaskellという一般の人には理解できない言語を日常的に使い、その特性にあるように完全に純粋で、自分たちを第一級オブジェクトとして扱う為、建設的な議論が困難です。テンプレートの話に戻りましょう。floatはもちろん、ユーザー定義の型であっても、適切に*(int)演算子が定義されていれば倍にして返してくれます。一度コードを書くだけで、型毎に自動的に関数を生成してくれる為、非常に柔軟で楽チンですが、それでも万能ではありません。特定の型の時だけ振る舞いを変えたい場合も出てきます。文字列に対して倍にするって何だ?みたいな話があるので、文字列型に対してx2が呼ばれた場合は、受け取った文字列を2回繰り返した文字列にして返すようにしてみましょう。t;}std::stringを受け取った場合はこちらのx2が呼ばれます。これをテンプレートの特殊化といいます。この場合はx2()をstd::stringに対して特殊化しました。teppyC++では、一般的に戻り値だけが異なるメソッドをオーバーライドすることはできません。エラー!戻り値型が違うぞ!};引数が違えば別関数と扱われ、単にメソッドが増えるだけなのですが、引数が同じ場合はオーバーライド対象なので、このコードはコンパイルエラーとなります。戻り値の型が異なっていても、その型が共変型であるならばコンパイルエラーにはなりません。オーバーライドする仮想関数の戻り値の型は、オーバーライド元の関数のものと同じか、または「共変(covariant)」でなければならない。__C++ランゲージクイックリファレンス......聞き慣れないですね。要するに「戻り値の型がクラス型の参照かポインタで、かつis-a関係にあるもの」に関しては親クラスと異なる型の戻り値であってもオーバーライドできますよっていう話です。何はともあれ、まずはis-a関係を持つ型を用意します。{};先ほどのエラーになったオーバーライドの例の戻り値に今定義した型ShapeとBoxを指定します。こんどは戻り値の型が共変なのでOK!};コンパイルは通りますが、共変型を持つメソッドはオーバーライドの挙動が通常のオーバーライドと異なるので注意が必要です。以下のプログラムでは結果として”shape”と表示されます。0;}Wandboxで確認Boxと表示されそうな気がしますが、実際にはshapeと表示されます。ここが超重要なのですが、Shape*を返してもb->get()は決してBase::get()の呼び出しでは無いということです。ポリモーフィズムの挙動に準じて、あくまでDerived::get()が呼び出されますが、操作しているポインタbの型次第で、Derived::get()で指定した型Box*のまま戻り値が返されるか、Base::get()で指定した型に暗黙に変換された後、返されるかという挙動の違いが発生します。慣れないとちょっと分かりづらいですね。したらC++の挙動の中でトップレベルの分かりづらさかもしれないですね。一応、共変型に対してオーバーライドのルールが緩和される為、純粋仮想関数による子クラスへの関数定義の強制のメリットと実際に取得する型が親クラスに引っ張られないメリットを享受できる......ということになっています。自分自身の型を返す関数を定義する時など、親クラス固定だと、受け取った側でのキャストが面倒ですしね。共変型の戻り値には、常に適切な抽象レベルで作業できるという利点があります。(中略)共変型の戻り値を使用すれば、ミスを誘いがちなキャストを使用したために、そもそも失うはずの無かった型情報を再度提供するはめになることもありません。teppyinline関数やconst変数を使ってもC言語時代に#defineマクロによって実現していたことの全てをカバーできるわけではありません。Processor)の力は偉大です。ビルドレベルに応じて違う挙動になるような処理を実現するには#defineによるマクロは有効な選択です。while(0)#endif以下のように使います。0;}DEBUG_LOGの定義を見て下さい。マクロで展開したい実際の処理(std::printf)をdo{...}while(0)で囲んでます。これはどういう意図でしょうか。do{...}while(0)としたところで、内部のステートメントは1度しか実行されません。((!exp)){std::printf(__VA_ARGS__)}と書くのと処理的には何も変わらないように見えます。実際には後者の定義は行末の;(セミコロン)を強制できない記述する場所によっては意図しない挙動になるビルドレベルによって記述できる箇所が変わるという3点の理由により全く不十分なのです。順番に見てみましょう。1.行末の;(セミコロン)を強制できないdo-while(0)じゃないバージョンでは行末の;(セミコロン)を強制できません。0;}このように展開されるのでセミコロンが無くてもc++のシンタックス上は問題の無いコードになります。これはc++のシンタックスに準じていないし、コード全体の一貫性も欠くことになります。書けてしまうというのは使う側ではなく、定義した側の責任です。2.記述する場所によっては意図しない挙動になるこのマクロがブロック無しif文の直後で呼ばれた時に意図しない挙動になります。nullptr;ブロック無しif文なんて書くな、カッコ悪いぞ!っていう話ではあるのですが、こう書いた時に以下のように展開されます。(p)と対だったはずのelse節がマクロから展開された方のif文との対になってしまいました。これも使う側ではなく、定義した側の責任です。do-whileで囲んだ最初の定義だと以下のように展開されます。nullptr;3.ビルドレベルによって記述できる箇所が変わるマクロが展開を展開した時にシンタックスエラーになるケースが変わります。なんか処理}if文だけのマクロの場合はこのような書式がc++的に許されてしまいます。デバッグビルド時は問題無いのに、いざリリースしようとするとコンパイルエラーになってしまいます。同じことが非デバッグ時のDEBUG_LOGの定義にも言え、例えば((void)0)を書かずに、展開結果をただ空白にしてしまうと、非デバッグビルド時には、どこにでも記述できるというマクロになってしまいます。0;}このように書いてもエラーになりません。マクロはc++のシンタックスを無視して、どこにでも記述できてしまいます。どこにでも記述させたい明確な理由が無い場合、このような記述はできるべきではありませんし、そもそもデバッグビルド時と記述可能箇所のルールが変わってしまいます。ビルドレベルによって記述可能箇所のルールが変わるのは、単に分かりづらい上に、ビルドレベルを変えたタイミングで、初めてコーディングのミスに気づくことになるので効率も悪いです。いうスキルレベルのプログラマに使われても不具合が起こりにくくなるように、可能な限り、紛れの無いコーディングを促すような設計を心がけましょう。teppy継承には3つのレベルがあります。publicprotectedprivateオブジェクト指向的な考え方ではpublic継承はよくis-a関係を表すなどと言われたりしますね。