オブジェクトの型がC ++の特定のサブクラスであるかどうかを確認するにはどうすればよいですか?
-
08-07-2019 - |
質問
typeid()
の使用に沿って考えていましたが、その型が別のクラスのサブクラスであるかどうかを確認する方法がわかりません(ところで、抽象クラスです)
解決
本当にすべきではありません。プログラムがオブジェクトがどのクラスであるかを知る必要がある場合、それは通常、設計上の欠陥を示しています。仮想関数を使用して、必要な動作を取得できるかどうかを確認してください。また、何をしようとしているかについての詳細情報が役立ちます。
次のような状況があると仮定しています:
class Base;
class A : public Base {...};
class B : public Base {...};
void foo(Base *p)
{
if(/* p is A */) /* do X */
else /* do Y */
}
これがあなたの持っているものなら、次のようなことをしてください:
class Base
{
virtual void bar() = 0;
};
class A : public Base
{
void bar() {/* do X */}
};
class B : public Base
{
void bar() {/* do Y */}
};
void foo(Base *p)
{
p->bar();
}
編集:この答えについての議論は何年もたった今でも続いているので、私はいくつかの参考文献を入れるべきだと思いました。基本クラスへのポインターまたは参照があり、コードがオブジェクトの派生クラスを知る必要がある場合、リスコフ置換原理。 ボブおじさんはこれを<!> quot; オブジェクト指向デザインへのアナタ <!> quot;。
他のヒント
<!> nbsp;
class Base
{
public: virtual ~Base() {}
};
class D1: public Base {};
class D2: public Base {};
int main(int argc,char* argv[]);
{
D1 d1;
D2 d2;
Base* x = (argc > 2)?&d1:&d2;
if (dynamic_cast<D2*>(x) == nullptr)
{
std::cout << "NOT A D2" << std::endl;
}
if (dynamic_cast<D1*>(x) == nullptr)
{
std::cout << "NOT A D1" << std::endl;
}
}
dynamic_cast
で実行できます(少なくとも多相型の場合)。
実際、考え直して-<=>で特定のタイプかどうかはわかりませんが、そのタイプかそのサブクラスかはわかります。
template <class DstType, class SrcType>
bool IsType(const SrcType* src)
{
return dynamic_cast<const DstType*>(src) != nullptr;
}
dynamic_cast
は、型に継承階層の任意の場所にターゲット型が含まれているかどうかを判断できます(はい、B
がA
およびC
を継承する場合、<= >直接A*
に)。 C*
は、オブジェクトの正確なタイプを判別できます。ただし、これらは両方とも非常に控えめに使用する必要があります。既に述べたように、動的な型識別は設計上の欠陥を示しているため、常に避けるべきです。 (また、オブジェクトが確実にターゲットタイプであることがわかっている場合は、typeid()
でダウンキャストを実行できます。Boostは、デバッグモードでstatic_cast
およびpolymorphic_downcast
でダウンキャストを実行するassert
を提供します。リリースモードでは、<=>)を使用します。
C ++でオブジェクトの型をチェックしたくないことには同意しません。あなたがそれを避けることができるなら、私はあなたがそうすべきであることに同意します。しかし、どんな状況でもこれを絶対にしないでくださいと言うのは行き過ぎです。非常に多くの言語でこれを行うことができ、あなたの人生をずっと楽にすることができます。たとえば、Howard Pinsleyは、C#に関する彼の投稿でその方法を示しました。
私はQt Frameworkで多くの仕事をしています。一般的に、私は彼らが物事を行う方法の後に私が行うことをモデル化します(少なくともそのフレームワークで作業する場合)。 QObjectクラスは、すべてのQtオブジェクトの基本クラスです。そのクラスには、サブクラスのクイックチェックとしてisWidgetType()およびisWindowType()関数があります。それでは、独自の派生クラスを確認できないのはなぜですか?以下は、これらの他の投稿の一部から派生したQObjectです:
class MyQObject : public QObject
{
public:
MyQObject( QObject *parent = 0 ) : QObject( parent ){}
~MyQObject(){}
static bool isThisType( const QObject *qObj )
{ return ( dynamic_cast<const MyQObject*>(qObj) != NULL ); }
};
そして、QObjectへのポインターを渡すとき、静的メンバー関数を呼び出すことで、それが派生クラスを指しているかどうかを確認できます。
if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";
あなたの問題を正しく理解しているかどうかわからないので、自分の言葉でもう一度言いましょう...
問題:クラスB
およびD
を指定して、TypeManip.h
がSuperSubclass
のサブクラスである(またはその逆ですか)かどうかを判断します
解決策:テンプレートの魔法を使用してください!さて、真剣に、LOKIを見てみる必要があります。LOKIは、有名なC ++の作者であるAndrei Alexandrescuが作成した優れたテンプレートメタプログラミングライブラリです。
具体的には、 LOKI をダウンロードしてヘッダー< =>ソースコードでそれから、次のようにSuperSubClass<B,D>::value
クラステンプレートを使用します。
if(SuperSubClass<B,D>::value)
{
...
}
ドキュメントによると、dynamic_cast
が<=>のパブリックベースである場合、または<=>と<=>が同じタイプのエイリアスである場合、<=>は真になります。
i.e。 <=>は<=>のサブクラスであるか、<=>は<=>と同じです。
これが役立つことを願っています。
編集:
<=>を使用する一部のメソッドとは異なり、コンパイル時に<=>の評価が行われることに注意してください。したがって、実行時にこのシステムを使用してもペナルティはありません。
#include <stdio.h>
#include <iostream.h>
class Base
{
public: virtual ~Base() {}
template<typename T>
bool isA() {
return (dynamic_cast<T*>(this) != NULL);
}
};
class D1: public Base {};
class D2: public Base {};
class D22: public D2 {};
int main(int argc,char* argv[]);
{
D1* d1 = new D1();
D2* d2 = new D2();
D22* d22 = new D22();
Base* x = d22;
if( x->isA<D22>() )
{
std::cout << "IS A D22" << std::endl;
}
if( x->isA<D2>() )
{
std::cout << "IS A D2" << std::endl;
}
if( x->isA<D1>() )
{
std::cout << "IS A D1" << std::endl;
}
if(x->isA<Base>() )
{
std::cout << "IS A Base" << std::endl;
}
}
結果:
IS A D22
IS A D2
IS A Base
RTTIを使用しない限り、テンプレートを使用してコンパイル時にのみ実行できます。
typeid関数を使用して、タイプに関する情報を含むtype_info構造体へのポインターを生成できます。
でそれを読んでください。c#では、単に次のように言うことができます。
if (myObj is Car) {
}
私は
を使用するラインに沿って考えていましたtypeid()
...
まあ、はい、比較できます:typeid().name()
。すでに説明した状況をとる場合、次のとおりです。
class Base;
class A : public Base {...};
class B : public Base {...};
void foo(Base *p)
{
if(/* p is A */) /* do X */
else /* do Y */
}
foo(Base *p)
の可能な実装は次のとおりです。
#include <typeinfo>
void foo(Base *p)
{
if(typeid(*p) == typeid(A))
{
// the pointer is pointing to the derived class A
}
else if (typeid(*p).name() == typeid(B).name())
{
// the pointer is pointing to the derived class B
}
}