《090》dynamic_cast演算子の利用(2)


 dynamic_cast演算子の利用(2. 参照型のキャスト

 dynamic_cast演算子で参照型の動的な型変換を行う場合、キャストに失敗すると例外 bad_cast が送出されます。

 次のプログラムの関数 func は、引数に渡されるオブジェクトが Aaa型であるか否か、を判定します。
ただし、渡されるオブジェクトは、すべて型 Base から派生したものであるということは分かっているものとします。

以下は、プログラムです。なお、出力結果は前回《089》と同じなので、省略します。
#include <iostream>
using namespace std;

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

class Aaa : public Base {
};

class Bbb : public Base {
};

void func(Base& r) {
    try {
        Aaa& ref = dynamic_cast<Aaa&>(r);
        // キャストに失敗した場合は、
        //   例外 bad_cast が送出されます。
        cout << "Aaa型です。\n";
    }
    catch (bad_cast) {
        cout << "Aaa型ではありません。\n";
    }
}

int main() {
    Aaa x1, x3;
    Bbb x2, x4;

    cout << "(1) "; func(x1);
    cout << "(2) "; func(x2);
    cout << "(3) "; func(x3);
    cout << "(4) "; func(x4);
}




2018-04-17 00:19 : 未分類 : コメント : 0 :

《089》dynamic_cast演算子の利用(1)


 dynamic_cast演算子の利用(1. ポインタ型のキャスト

 前回《088》確認したように、dynamic_cast演算子でポインタの動的な型変換を行う場合、キャストに失敗すると空ポインタが生成されます。

 次のプログラムの関数 func は、引数に渡されるオブジェクトが Aaa型であるか否か、を判定します。
ただし、渡されるオブジェクトは、すべて型 Base から派生したものであるということは分かっているものとします。

以下は、プログラムです。
#include <iostream>
using namespace std;

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

class Aaa : public Base {
};

class Bbb : public Base {
};

void func(Base* p) {
    Aaa* ptr = dynamic_cast<Aaa*>(p);
    // キャスト成功ならば ptr はアドレス値、
    //         失敗ならば ptr は空ポインタ。

    if (ptr)
        cout << "Aaa型です。\n";
    else
        cout << "Aaa型ではありません。\n";
}

int main() {
    Aaa x1, x3;
    Bbb x2, x4;

    cout << "(1) "; func(&x1);
    cout << "(2) "; func(&x2);
    cout << "(3) "; func(&x3);
    cout << "(4) "; func(&x4);
}

fca05_0014.png

2018-04-17 00:08 : 未分類 : コメント : 0 :

《088》dynamic_cast演算子


 dynamic_cast演算子による動的キャスト

 dynamic_cast演算子は、多相的クラスの動的キャストを行う演算子です。

キャストに失敗した際の、dynamic_cast演算子の挙動
  ポインタの場合
   キャストにより生成されるポインタは、変換先の型をもつ空ポインタとなります。
  参照の場合
   例外 bad_cast が送出されます。

以下は、プログラムです。
#include <iostream>
using namespace std;

class Base {
public:
    // 仮想デストラクタを持つので
    //           Base は多相的クラスです。
    virtual ~Base() { }
};

// Derived は public派生クラス
class Derived : public Base { };

int main()
{
    Base b;
    Derived d;

    cout << "◆ポインタ型のダウンキャスト\n";
    cout << "Derived* p1 = dynamic_cast<Derived*>(&b);\n";
    Derived* p1 = dynamic_cast<Derived*>(&b);
    if (p1) cout << "成功\n"; else cout << "失敗\n";
    cout << "&b _ " << &b << '\n';
    cout << "p1 _ " << p1 << "\n\n";

    cout << "◆ポインタ型のアップキャスト\n";
    cout << "Base* p2 = dynamic_cast<Base*>(&d);\n";
    Base* p2 = dynamic_cast<Base*>(&d);
    if (p2) cout << "成功\n"; else cout << "失敗\n";
    cout << "&d _ " << &d << '\n';
    cout << "p2 _ " << p2 << "\n\n";

    cout << "◆参照型のダウンキャスト\n";
    cout << "Derived& r1 = dynamic_cast<Derived&>(b);\n";
    try {
        Derived& r1 = dynamic_cast<Derived&>(b);
        cout << "成功\n";
    }
    catch (bad_cast e) {
        cout << "失敗\n";
        cout << e.what() << "\n\n";
    }

    cout << "◆参照型のアップキャスト\n";
    cout << "Base& r2 = dynamic_cast<Base&>(d);\n";
    try {
        Base& r2 = dynamic_cast<Base&>(d);
        cout << "成功\n";
    }
    catch (bad_cast e) {
        cout << "失敗\n";
        cout << e.what() << '\n';
    }
}

fca05_0013.png

2018-04-17 00:03 : 未分類 : コメント : 0 :

《087》bad_typeidクラス


 bad_typeidクラス

 typeid演算子は、多相的クラス型へのポインタによる参照を受け取ると、その参照先の動的なオブジェクト型を表す type_infoオブジェクトを生成します。
そして、その type_infoオブジェクトへの参照が typeid演算子の演算結果です。

 typeid演算子が、多相的クラス型へのポインタによる参照を受け取った際に、そのポインタが空ポインタであった場合には、例外 bad_typeid が送出されます。
bad_typeidクラスは、exceptionクラスの派生クラスで、<typeinfo>ヘッダで提供されます。

 次のプログラムは、以上のことを確認するためのものです。
#include <exception>
#include <typeinfo>
#include <iostream>
using namespace std;

class Aaa {
public:
    virtual void f() { }
};

int main() {
    Aaa aaa;

    // Aaa*型ポインター p1 は aaa を指します。
    Aaa* p1 = &aaa;

    // Aaa*型ポインター p2 は NULL
    Aaa* p2 = NULL;

    try {
        cout << typeid(*p1).name() << endl;
    }
    catch (bad_typeid e) {
        cout << e.what() << endl;
    }

    try {
        cout << typeid(*p2).name() << endl;
    }
    catch (bad_typeid e) {
        // bad_typeidクラスのメンバ関数 what
        //         は、処理系定義の
        //         NTBS(C言語形式の文字列)
        //         を返却します。
        cout << e.what() << endl;
    }
}

fca05_0011.png

 なお、プログラム中の、virtual(赤文字で示してあります)を削除すると、
次のような結果になります。
fca05_0012.png


2018-04-14 00:28 : 未分類 : コメント : 0 :

《086》type_infoクラス


 type_infoクラス

 type_infoクラスは、型情報を格納した型であり、<typeinfo>ヘッダによって提供されます。

 typeid演算子によってのみ生成される type_infoオブジェクトには、型名文字列へのポインター その他の型情報が格納されています。
( typeid演算子が生成するのは、const std::type_info型の左辺値です。typeid演算子の結果は、その参照になります。)

 typeid演算子に型 あるいは オブジェクトを渡すことにより生成される type_infoオブジェクトは、その型 あるいは オブジェクト の実行時型情報 RTTI です。


 type_infoクラスの定義は、概略としては、以下のようになっています。
   class type_info {
   public:
     virtual ~type_info();
     bool operator==(const type_info&) const;
     bool operator!=(const type_info&) const;
     const char* name() const;
     ・・・
    private:
     type_info(const type_info&);
     type_info& operator=(const type_info&);
   };


メンバ関数 name は、処理系定義の NTBS を返却します。
 ( NTBS … Null-Terminated Byte String のことで、末尾がナル文字になっている C言語形式の文字列です。)
type_info コピーコンストラクターは private であるため、type_infoクラスのオブジェクトを直接インスタンス化することはできません。
 ( type_info オブジェクトの生成は、typeid 演算子によってのみ可能です。)
代入演算子「 = 」も private です。したがって、type_infoオブジェクトのコピーや代入を行うことはできません。
コピーコンストラクタと代入演算子を private: で宣言することで、オブジェクトのコピーを抑止することができます。

#include <typeinfo>
#include <iostream>

int main() {
    std::cout << typeid(int).name() << '\n';

    const type_info& ref = typeid(unsigned);
    std::cout << ref.name() << '\n';

    const type_info* ptr = &typeid(double);
    std::cout << ptr->name() << "\n\n";

    // operator==
    std::cout << std::boolalpha
        << (typeid(int) == typeid(5)) << '\n';

    // operator!=
    std::cout
        << (typeid(int) != typeid(5)) << '\n';
}

fca05_0010.png

2018-04-14 00:27 : 未分類 : コメント : 0 :
ホーム  次のページ »

検索フォーム

こうすけ kousuke_cpp@outlook.jp

スポンサーリンク

新版 明解C 中級編 (明解シリーズ)

新品価格
¥2,916から
(2018/3/24 23:58時点)