2016-08-25 4 views
3

私はすべてのクラスが直接的または間接的に基底クラスBaseから派生し、名前を持つクラスライブラリを扱っています。ライブラリは、名前でオブジェクトを検索する機能を提供し、Base*を返します。実行時にオブジェクトの型をポインタから基本クラスに戻す

次の例のように、dynamic_castを使用してすべての可能性をチェックせずに返されるオブジェクトの型を見つける方法はありますか?可能であれば、派生したクラスにテンプレートパラメータがあるので、これを避けたいと思います。これはかなりの可能性をもたらします。

テンプレートタイプを知らなくても、クラスタイプ(以下の例ではT1またはT2)を少なくとも見つけられればいいです。 dynamic_cast<T1<i_dont_care>*>のようにしてください。

#include <iostream> 

using namespace std; 

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

template <typename T> class T1 : public Base {}; 
template <typename T> class T2 : public Base {}; 

Base *find_by_name() { 
    return new T2<int>(); 
} 

int main() { 
    Base *b = find_by_name(); 

    if (T1<int> *p = dynamic_cast<T1<int>*>(b)) { 
     cout << "T1<int>" << endl; 
     // do something meaningful with p 
    } else if (T1<double> *p = dynamic_cast<T1<double>*>(b)) 
     cout << "T1<double>" << endl; 
    else if (T2<int> *p = dynamic_cast<T2<int>*>(b)) 
     cout << "T2<int>" << endl; 
    else if (T2<double> *p = dynamic_cast<T2<double>*>(b)) 
     cout << "T2<double>" << endl; 
    else 
     cout << "unknown" << endl; 

    delete b; 

    return 0; 
} 

上記の例は簡略化されています。それぞれifで私はpと意味のある何かをしたいと思います。

私はこれが最初から悪いデザインであることを認識していますが、私はこのライブラリに悩まされていますし、その実装を変更する方法もありません。

+0

は、 'B'は、それを行うためのメンバーを持っている必要があります。また、 'typeid(* b).name()'を調べることもできます。 –

+0

あなたの 'p'は全て冗長です。' if(dynamic_cast *>(b)) ' –

+0

' Base'は本当に他のメンバーを持っていませんか?これは、ライブラリが提供すべき機能のようなものです。普通のポインタでできることはあまりありません。 – juanchopanza

答えて

3

あなたは型の名前を取得することが可能なstd::type_infoのインスタンスを返しますtypeidオペレータは、あります。

それがあなたに役立つかどうかわかりません。最初に、返された名前は、実装全体で同じであることが保証されていません。第二に、一度名前をつけたら何をしますか?あなたはおそらくあらかじめ定義された名前と比較しますが、おそらくdynamic_castの束よりも遅いでしょう。

Baseクラスまたは階層の新しい中間層にタイプサポートが組み込まれていない場合は、dynamic_castが最適です。実際には非常に高速です(通常は1つの比較命令のみ)。私が意味する中間層によって

:この機能が必要な場合は

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

class T1Base : public Base {}; 
class T2Base : public Base {}; 

template <typename T> class T1 : public T1Base {}; 
template <typename T> class T2 : public T2Base {}; 

int main() { 
    Base *b = find_by_name(); 

    if (dynamic_cast<T1Base*>(b)) 
     cout << "T1" << endl; 
    else if (dynamic_cast<T2Base*>(b)) 
     cout << "T2" << endl; 
    else 
     cout << "unknown" << endl; 

    delete b; 

    return 0; 
} 
+0

この回答を受け入れることで、最良の選択肢を指摘しています。 'dynamic_cast'の豊富さはそれです... – rainer

3

typeidhttp://en.cppreference.com/w/cpp/language/typeidのようなものがあります。これは、多型表現に適用され、実行時にその型表現に評価されます。ウィキ例に続き

https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast

#include <iostream> 
#include <typeinfo> // for 'typeid' 

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

class Employee : public Person { 
}; 

int main() 
{ 
    Person person; 
    Employee employee; 
    Person* ptr = &employee; 
    Person& ref = employee; 
    // The string returned by typeid::name is implementation-defined 

    // Person (statically known at compile-time) 
    std::cout << typeid(person).name() << std::endl; 

    // Employee (statically known at compile-time) 
    std::cout << typeid(employee).name() << std::endl; 

    // Person* (statically known at compile-time) 
    std::cout << typeid(ptr).name() << std::endl;  

    /* Employee (looked up dynamically at run-time 
    * because it is the dereference of a 
    * pointer to a polymorphic class) */ 
    std::cout << typeid(*ptr).name() << std::endl;  

    // Employee (references can also be polymorphic)   
    std::cout << typeid(ref).name() << std::endl;  

}

関連する問題