zxc さんが書きました: 下のコードもVC++2010では通るようです。ideoneで何故通らないかは分かりません。
コード:
#include<iostream>
#include<typeinfo>
class weather{};
template<typename T>
class T{};
int main(){
using namespace std;
return 0;
}
VC++のバグじゃないでしょうか。どっちにしろC++でこの構文は使えません。
zxc さんが書きました:
Report関数について:簡単に纏めると現在の状態を型で判断しようと思っていて、現在の状態を知るために子クラスに自身の型を返させる(=Report関数)という方法をとったからです。
(状態の切り替えはマネージャに全部任せるつもりです。マネージャは与えられた条件で状態を切り替えますが、切り替える前に変更後の状態と現在の状態が同じであれば切り替えません。今考えている設計が、変更後の状態はマネージャが他所から受け取り、現在の状態は子クラスからのReport関数で、親クラスのポインタへ受け取る設計だからです。)
現在の状態と同じものが変更後の状態としてマネージャーに渡されるような設計自体がおかしいと思います。
zxc さんが書きました:
まず前提として、それぞれの子クラスにReport関数を記述するのは面倒なので、Report関数を他の方法ですべての子クラスに持たせることを考えています。
誤ったキャストについては純粋仮想関数は間違いでただの継承です。すみませんでした。親クラスでReport関数をもって、それぞれのクラスの型のポインタにキャストする際に、別の子クラス型にキャストしてしまうとバグがあっても気づきにくいと言うことです。下ではtypeidの中でキャストしていないので、親クラスの型ポインタのままになります。それ以外にも問題多いのでこの方法は避けました。
ステートの管理は「親クラスの型ポインタのまま」使うのが普通であって、子クラス型にダウンキャストして使うのは設計がおかしいです。
それだったら継承を使っている意味がありませんよね。
ちなみにCスタイルキャストは危険なので使わないでください。
dynamic_castを使えば安全にダウンキャストをすることができます。
zxc さんが書きました:
誤った型の決定については下のようにしてしまうと、自身の型ではないポインタを返せます。文法上誤りではないとおもうので気づきにくいと思うのです。
コード:
class weather{};
template<typename T>
class TempReport:virtual public weather{
public:
T* Report(){return (&T);}
};
class rainy:public TempReport<rainy>{・・・・・・};
class sunny:public TempReport<rainy>{・・・・・・};////templateはsunnyにすべき
まず return (&T); がC++の文法として不正です。(定数のアドレスを取ることはできない)
VC++は不正な文法でもエラーを出さなかったりするので注意してください。
RTTIに頼るより、ユニークなidをenumなどでクラスごとにもってReportでそれを返すほうが素直な実装ではないかと。
このコードと同様にクラスに間違ったidを振ってしまう可能性もありますが、この手のミスをコンパイル時に判断させるのは限界があると思います。