2012-03-05 13 views
5

テンプレート派生型にベースポインタからダウンキャスト

class base 
{ 
public: 
    virtual ~base(){} 
    virtual void foo() {} 
}; 

template <typename T> 
class derived1 : public base 
{ 
    virtual void foo() {}; 
}; 

template <typename T> 
class derived2 : public base 
{ 
    virtual void foo() {}; 
}; 

今ベースへのポインタを与え、私は基礎となる がderived1かderived2のどちらかであるかどうかを確認したいと思います。問題は、 derived1とderived2の両方が多くの異なる タイプで特殊化できることです.Downcastをテストするためにdynamic_castを使用すると、 テンプレートタイプを知る必要があります。私はコードの、乱雑unmaintableと不完全ビットになってしまっている:

base* b = new derived1<int>(); 

if (dynamic_cast<derived1<int>*> || 
    dynamic_cast<derived1<unsigned int>*> || 
    dynamic_cast<derived1<double>*>) 
    std::cout << "is derived1"; 
else if (dynamic_cast<derived2<int>*> || 
    dynamic_cast<derived2<unsigned int>*> || 
    dynamic_cast<derived2<double>*>) 
    std::cout << "is derived2"; 

は、任意のタイプの特殊化を扱うことができる良い方法は、ありますか?

+2

タイプが派生テンプレートの1つの特殊化であることがわかったらどうしますか? –

+0

@James:各関数に特定の関数を呼び出す - btwにはderived1とderived2以上がある –

+6

基本クラスポインタの具体的な型を動的にテストする必要のある条件付きコードは、悪いコードの匂いです。おそらく、これを避けるためにデザインを変更する方法があります。 –

答えて

8

タイプに依存するロジックをタイプに移動します。

の代わりに:

if (dynamic_cast<derived1<int>*>(b) || 
    dynamic_cast<derived1<unsigned int>*>(b) || 
    dynamic_cast<derived1<double>*>(b)) 
    std::cout << "is derived1"; 
else if (dynamic_cast<derived2<int>*>(b) || 
    dynamic_cast<derived2<unsigned int>*>(b) || 
    dynamic_cast<derived2<double>*>(b)) 
    std::cout << "is derived2"; 

basevirtual print_name() const機能を追加し、実行します。

void example() { 
    std::unique_ptr<base> b(new derived1<int>()); 
    b->print_name(); 
} 
class base 
{ 
public: 
    ~base(){} 
    virtual void foo() {} 
    virtual void print_name() const = 0; 
}; 

template <typename T> 
class derived1 : public base 
{ 
    virtual void foo() {} 
    virtual void print_name() const { 
     std::cout << "is derived1"; 
    } 
}; 

template <typename T> 
class derived2 : public base 
{ 
    virtual void foo() {} 
    virtual void print_name() const { 
     std::cout << "is derived2"; 
    } 
}; 
6

basederived1またはderived2わたってるしき非テンプレートクラスを挿入します。

class base 
{ 
public: 
    virtual ~base() {} // **NOTE** Should be virtual 
    virtual void foo() {} 
}; 

class derived1_base : public base 
{ 
}; 

template <typename T> 
class derived1 : public derived1_base 
{ 
public: 
    virtual void foo() {} 
}; 

class derived2_base : public base 
{ 
}; 

template <typename T> 
class derived2 : public derived2_base 
{ 
public: 
    virtual void foo() {} 
}; 

コメントでは、あなたが言及した:

をそれぞれに対して特定の関数を呼び出す[私がしたい] - ところで以上の derived1とderived2

derived1_baseには、(仮想)機能を追加しますがあります、あなたはもうTを知る必要はありません。

if (dynamic_cast<derived1_base*>(foo)) 
{ 
    std::cout << "is derived1"; 
    dynamic_cast<derived1_base*>(foo)->specific_derived1_function(); 
} 
else if (dynamic_cast<derived2_base*>(foo)) 
{ 
    std::cout << "is derived2"; 
    dynamic_cast<derived2_base*>(foo)->specific_derived2_function(); 
} 

NOTE:私はdynamic_cast<>コードのにおいのリストを考えると、私はあなたのアプローチを再考するよう強くお勧めします。

2

解決方法1:

enum DerivedType 
{ 
    One, 
    Two, 
    ... 
}; 

class base 
{ 
public: 
    ~base(){} 
    virtual void foo() {} 
    virtual DerivedType GetType() = 0; 
}; 

template <typename T> 
class derived1 : public base 
{ 
    virtual void foo() {}; 
    virtual DerivedType GetType() { return One; } 
}; 

template <typename T> 
class derived2 : public base 
{ 
    virtual void foo() {}; 
    virtual DerivedType GetType() { return Two; } 
}; 

解決策2:使用してタグのクラス:1以上の仮想関数を追加

class Base 
{ 
public: 
    virtual ~Base() { } 
}; 

class Derived1Tag 
{ }; 

class Derived2Tag 
{ }; 

template <class T> 
class Derived1 : public Base, public Derived1Tag 
{ }; 

template <class T> 
class Derived2 : public Base, public Derived2Tag 
{ }; 


int main(int argc, char** argv) 
{ 
    Derived1<int> d1; 
    Derived2<int> d2; 

    cout << dynamic_cast<Derived1Tag*>((Base*)&d1) << endl; 
    cout << dynamic_cast<Derived1Tag*>((Base*)&d2) << endl; 

    return 0; 
} 
+0

私は@EmileCormierが正しく、この**おそらく**はどこかの悪いデザインの選択肢を反映していると言わなければなりません。実行する関数が型に依存する場合は、おそらく最初から仮想関数でなければなりません。 –

3

あなたはいくつかの種類のメタ型チェックを行うには、仮想メソッドを追加することができます:

class base 
{ 
public: 
    ~base(){} 
    virtual void foo() {} 
    virtual bool isa(const char* type_to_test){ 
      return strcmp(type_to_test,"base")==0;} 
}; 

template <typename T> 
class derived1 : public base 
{ 
    virtual void foo() {}; 
    virtual bool isa(const char* type_to_test){ 
    return strcmp(type_to_test,"derived1")==0;} 
}; 
関連する問題