C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でJavaのinstanceof相当の処理を実現する方法

C++には、あるオブジェクトが特定のクラス型のインスタンスであるかどうかを直接判定する組み込みの仕組みがありません。Javaであればinstanceof演算子を使うだけで簡単に確認できますが、C++では別のアプローチが必要です。

C++11にはstd::is_base_of<Base, T>という型トレイトが用意されています。これは指定したクラスが別のクラスの基底クラスであるかどうかをコンパイル時にチェックするものです。しかし、これはあくまで型同士の継承関係を調べるだけで、実行時に渡されたオブジェクトの実際の型までは検証できません。

dynamic_castを使ったinstanceofの実現

Javaのinstanceofに最も近い動作を実現するには、dynamic_cast<new-type>(expression)を使用します。dynamic_castは、与えられたポインタや参照を指定した型への変換を試みます。変換が成功すればその型のポインタが返され、失敗した場合はヌルポインタ(nullptr)が返されます。この結果を利用することで、オブジェクトが目的のクラス(またはその派生クラス)のインスタンスかどうかを実行時に判定できます。

なお、dynamic_castが使えるのは以下の条件を満たす場合のみです。

  • 対象のクラスがポリモーフィック(少なくとも1つの仮想関数を持つ)であること
  • コンパイラのRTTI(実行時型情報)が有効になっていること

仮想デストラクタを持たないクラスなど、ポリモーフィックでない型に対してはコンパイルエラーになるため注意が必要です。

サンプルコード

#include <iostream>
using namespace std;

template<typename Base, typename T>
inline bool instanceof(const T *ptr) {
    return dynamic_cast<const Base*>(ptr) != nullptr;
}

class Parent {
    public:
    virtual ~Parent() {}
    virtual void foo () { std::cout << "Parent\n"; }
};

class Child : public Parent {
    public:
    virtual void foo() { std::cout << "Child\n"; }
};

class AnotherClass{};

int main() {

    Parent p;
    Child c;
    AnotherClass a;

    Parent *ptr1 = &p;
    Child *ptr2 = &c;
    AnotherClass *ptr3 = &a;

    if(instanceof<Parent>(ptr1)) {
        cout << "p is an instance of the class Parent" << endl;
    } else {
        cout << "p is not an instance of the class Parent" << endl;
    }

    if(instanceof<Parent>(ptr2)) {
        cout << "c is an instance of the class Parent" << endl;
    } else {
        cout << "c is not an instance of the class Parent" << endl;
    }

    if(instanceof<Child>(ptr2)) {
        cout << "c is an instance of the class Child" << endl;
    } else {
        cout << "c is not an instance of the class Child" << endl;
    }

    if(instanceof<Child>(ptr1)) {
        cout << "p is an instance of the class Child" << endl;
    } else {
        cout << "p is not an instance of the class Child" << endl;
    }

    if(instanceof<AnotherClass>(ptr2)) {
        cout << "c is an instance of AnotherClass class" << endl;
    } else {
        cout << "c is not an instance of AnotherClass class" << endl;
    }
}

実行結果

p is an instance of the class Parent
c is an instance of the class Parent
c is an instance of the class Child
p is not an instance of the class Child
c is not an instance of AnotherClass class

コードのポイント

このサンプルでは、テンプレート関数instanceofを定義することで、Javaのような自然な記述を可能にしています。内部ではdynamic_castの結果がnullptrかどうかを返しているだけです。

注目すべき挙動は次の通りです。

  • ChildParentを継承しているため、ChildのポインタはParentのインスタンスとして判定されます。
  • 逆に、ParentのポインタをChildとして判定すると失敗します。実際のオブジェクトがChildでないためです。
  • 継承関係にないAnotherClassとの判定も失敗します。

このように、dynamic_castベースのinstanceofは「実際のオブジェクトの型」に基づいて正確に判定できるのが大きな特徴です。ただし、頻繁な型チェックは設計上の問題を示唆していることも多いため、仮想関数によるポリモーフィズムで解決できないかを先に検討するのが望ましいでしょう。

  1. 【C++入門】多重継承の基本と実装方法をわかりやすく解説

    多重継承(Multiple Inheritance)とは多重継承とは、ひとつのクラスが複数の基底クラス(親クラス)から派生する仕組みのことです。多重継承を利用することで、派生クラスは複数の基底クラスが持つ機能やデータメンバをまとめて引き継ぐことができます。これはC++に代表されるオブジェクト指向プログラミング言語における重要な機能のひとつです。多重継承の構造を表した図が以下になります。C++で多重継承を実装するサンプルプログラムここでは、C++で多重継承を実装したサンプルプログラムを紹介します。クラスCが、クラスAとクラスBの2つのクラスを同時に継承する例です。サンプルコード#include

  2. C#のBigIntegerクラスとは?巨大な数値を扱う方法と主なコンストラクタを解説

    C#で通常の整数型(int や long)では表現できない非常に大きな数値を扱いたい場合には、BigInteger 構造体を使用します。BigInteger を利用するには、プロジェクトに System.Numerics アセンブリへの参照を追加する必要があります。BigInteger は System.Numerics.BigInteger 名前空間に定義されており、理論上はメモリが許す限り無限に近い大きさの整数を扱うことができます。暗号処理や科学技術計算など、桁あふれ(オーバーフロー)を気にせず正確な計算を行いたい場面で特に役立ちます。BigInteger の構文BigInteger の宣