web-dev-qa-db-ja.com

C ++でオブジェクトのタイプを見つける

クラスAと、それから継承する別のクラスBがあります。タイプAのオブジェクトをパラメーターとして受け入れる関数をオーバーライドしているため、Aを受け入れる必要があります。ただし、後でBのみが持つ関数を呼び出します。ですから、渡されたオブジェクトがタイプBでない場合はfalseを返し、処理を進めません。

私の関数に渡されたオブジェクトがどの型であるかを知る最良の方法は何ですか?

130
lemnisca

dynamic_castはトリックを行う必要があります

TYPE& dynamic_cast<TYPE&> (object);
TYPE* dynamic_cast<TYPE*> (object);

dynamic_cast キーワードは、データをあるポインターまたは参照タイプから別のタイプにキャストし、実行時チェックを実行してキャストの有効性を確認します。

実際のオブジェクトの型ではない型へのポインターにキャストしようとすると、キャストの結果はNULLになります。実際のオブジェクトの型ではない型への参照にキャストしようとすると、キャストは bad_cast 例外をスローします。

dynamic_castを機能させるために、Baseクラスに少なくとも1つの仮想関数があることを確認してください。

142
yesraaj

ダイナミックキャストは問題の説明に最適ですが、クラスタイプを見つけることができることを追加したいだけです。

#include <typeinfo>

...
string s = typeid(YourClass).name()
138
Robocide

これは RTTI と呼ばれますが、型を見つけてそれに基づいて特別なことを行うとコードがより脆弱になるため、ここで設計を再検討する必要があります。

23
Paul Betts

おそらくオブジェクトにID「タグ」を埋め込み、それを使用してクラスAのオブジェクトとクラスBのオブジェクトを区別します。

ただし、これは設計の欠陥を示しています。 AにはないBのメソッドは、Aの一部であるが空のままにして、Bがそれらを上書きすることが理想的です。これにより、クラス固有のコードが不要になり、OOPの精神に沿ったものになります。

9
freespace

dynamic_cast<B*>(pointer)を探しています

7
Joshua

完了するために、ロボサイドからビルドをビルドし、typeidがname()を使用せずに単独で使用できることを指摘します。

#include <typeinfo>
#include <iostream>

using namespace std;

class A {
public:
    virtual ~A() = default; // We're not polymorphic unless we
                            // have a virtual function.
};
class B : public A { } ;
class C : public A { } ;

int
main(int argc, char* argv[])
{
    B b;
    A& a = b;

    cout << "a is B: " << boolalpha << (typeid(a) == typeid(B)) << endl;
    cout << "a is C: " << boolalpha << (typeid(a) == typeid(C)) << endl;
    cout << "b is B: " << boolalpha << (typeid(b) == typeid(B)) << endl;
    cout << "b is A: " << boolalpha << (typeid(b) == typeid(A)) << endl;
    cout << "b is C: " << boolalpha << (typeid(b) == typeid(C)) << endl;
}

出力:

a is B: true
a is C: false
b is B: true
b is A: false
b is C: false
7
firebush

クラスはポリモーフィックではないためです。試してください:

struct BaseClas { int base; virtual ~BaseClas(){} };
class Derived1 : public BaseClas { int derived1; };

現在、BaseClasはポリモーフィックです。構造体のメンバーはデフォルトでパブリックであるため、クラスを構造体に変更しました。

3
c64zottel

他の人が示したように、dynamic_castを使用できます。ただし、一般的にdynamic_castを使用して、作業中の派生クラスのタイプを見つけることは、設計が悪いことを示しています。パラメーターとしてAのポインターを受け取る関数をオーバーライドする場合、クラスA自体のメソッド/データを処理できる必要があり、クラスBのデータに依存しないようにする必要があります。作成しているメソッドがクラスBのみで機能することを確認してから、クラスBに新しいメソッドを作成する必要があります。

3
Naveen

説明は少しわかりにくいです。

一般的に、一部のC++実装にはメカニズムがありますが、型について尋ねる必要はありません。代わりに、Aへのポインターでdynamic_castを実行することになっています。これにより、実行時に、Aへのポインターの実際の内容がチェックされます。 Bがある場合は、Bへのポインタを取得します。そうでない場合は、例外またはnullを取得します。

2
Uri

オーバーロードされた関数を使用します。 dynamic_castまたはRTTIサポートさえ必要ありません:

class A {};
class B : public A {};

class Foo {
public:
    void Bar(A& a) {
        // do something
    }
    void Bar(B& b) {
        Bar(static_cast<A&>(b));
        // do B specific stuff
    }
};
1
jmucchiello

ブーストライブラリにアクセスできる場合は、type_id_with_cvr()関数が必要であり、 provide削除しないデータ型const、volatile、&and && modifiers 。 C++ 11の簡単な例を次に示します。

#include <iostream>
#include <boost/type_index.hpp>

int a;
int& ff() 
{
    return a;
}

int main() {
    ff() = 10;
    using boost::typeindex::type_id_with_cvr;
    std::cout << type_id_with_cvr<int&>().pretty_name() << std::endl;
    std::cout << type_id_with_cvr<decltype(ff())>().pretty_name() << std::endl;
    std::cout << typeid(ff()).name() << std::endl;
}

これが役立つことを願っています。

1
Kehe CAI