ゲームを作っているとシーンclassみたいなものをだいたい使うわけですが
ついメインシーンclassとかにゲームのメイン部分を書いていっちゃうんですよね
でも、例えばチュートリアルシーンみたいなのを作りたくなったときとかにメインシーンとは別でメイン動作と同じものが必要になったとき、すべて移さなくちゃいけなくて大変だったりするんですよね
だから動作のclassを作ったうえでシーンclassに持たせてやるのがあとあと何かあったときに楽に移植できたりしていいなぁって思いますね
ずっとやりたかったけど、MSのサンプル見てても結構めんどくさくて困ってたんです
スタックオーバーフローでそれっぽいの見つけたので、ぽいぽいっと入れたらやっとできた
とりあえず一安心です。
困ったときはググろうな!!
そもそもテンプレートメソッドパターンとは、以下のようにアクセスするpublicのメンバ関数内で、(純粋)仮想関数などを使用し、決められた型にはまった動作を行うようにするデザインパターンです。
class Original { protected: int m_num; virtual int cal()const=0; public: Original(const int num): m_num(num) {} void value()const { cout << "値は:"<< this->cal()<<endl; } }; class Square : public Original { private: int cal() const override { return m_num*m_num; } public: Square(const int num): Original(num) {} }; //後で比較するためにあえてここに作る const Square num(2); void main() { num.value(); }
これの場合は
というだけの枠組みに決まったvalue()関数である。
ですがconstexprを学びだした僕はこう思ったわけです
ん?おいまてよ、これくらいならconstexprにしたいぞと、
ってことでconstexprにしてみる
class Original { protected: int m_num; virtual int hoge()const=0; public: constexpr Original(const int num): m_num(num) {} void value()const { cout << "値は:"<< this->hoge()<<endl; } }; class Square : public Original { private: int hoge() const override { return m_num*m_num; } public: constexpr Square(const int num): Original(num) {} }; constexpr Square num(2); void main() { num.value(); }
やってやったぞ!優勝!!!と思ったあなたは大間違い
これを実行すると…動作が停止します。
thisがねえって怒られます。
constexprはvirtualメソッドがNGって聞きます。つまりはダメ
ちなみに下みたいにしたら問題なく動いたのですが、その理由がわからない(T T)
void main() { constexpr Square num(2); num.value(); }
h内に書いたりした場合ももちろん動作は停止。
では、どうやって解決するかですが
templateを使って静的ポリモーフィズムのようにします
template<class _T> class Original { protected: int m_num; public: constexpr Original(const int num): m_num(num) {} void value()const { cout << "値は:"<< static_cast<const _T&>(*this).cal()<<endl; } }; class Square : public Original<Square> { friend class Original<Square>; private: int cal() const { return m_num*m_num; } public: constexpr Square(const int num): Original(num) {} };
おいおいfriendがでてきたぞと、
friendとはそのclassに自身のprivateやprotectedのメンバへのアクセスを許可するものです。
hogeをpublicにすればいいのですが、それではテンプレートメソッドを使ってるメリットがなくなってしまいます。
これでOKですが…
Originalにhogeさえ持ってればどんなclassでも_Tに渡せる状態なのでわりと危険かな
(static_castしてるのでそこでエラーは、はいてくれるが)
templateを使うたびにやばいこと(危険なこと)してる気がしてます。
関数のオーバーロードは静的に決まることを知らなくてはまったことがあったのでメモ
class Super { }; class Sub :public Super { }; void Piyo(const Super& super) { cout << "Super" << endl; } //関数のオーバーロード void Piyo(const Sub& sub) { cout << "Sub" << endl; } void main() { unique_ptr<Super> hoge = make_unique<Sub>(); Piyo(*hoge); }
これを実行すると何が表示されるでしょうか?
実行結果は
Super
です。
タイトル通り、関数のオーバーロードは静的に決まるので、hogeはunique_ptr< Super >からSuperとしか解決できません。
もしこういったことがしたい場合はvisiterパターンのような方法がひつようになります。
class Super { public : virtual void piyopiyo() { Piyo(*this); //おい、俺はSuperだぞ } }; class Sub :public Super { public: //関数のオーバーライドも忘れずに void piyopiyo()override { Piyo(*this); //おい、俺はSubやで^^ } }; void Piyo(const Super& super) { cout << "Super" << endl; } //関数のオーバーロード void Piyo(const Sub& sub) { cout << "Sub" << endl; } void main() { unique_ptr<Super> hoge = make_unique<Sub>(); hoge->piyopiyo(); }
これで実行結果は
Sub
となります。
書いていることは全く同じですが、派生classでオーバーライドを忘れないようにしましょう。
なんか書くかも