新規記事の投稿を行うことで、非表示にすることが可能です。
2017年12月22日
《その195》 例外クラス 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() { }
// クラス Aaa を多相的クラスにするために、
// 仮想メンバ関数を設定。
};
int main() {
Aaa aaa;
// Aaa型のオブジェクト aaa を作成。
Aaa* ptr1 = &aaa;
// Aaa*型ポインター ptr1 は aaa を指す。
Aaa* ptr2 = NULL;
// Aaa*型ポインター ptr2 は NULL
try {
cout << typeid(*ptr1).name() << endl;
}
catch (bad_typeid e) {
cout << e.what() << endl;
}
try {
cout << typeid(*ptr2).name() << endl;
}
catch (bad_typeid e) {
cout << e.what() << endl;
// what は bad_typeidクラスのメンバ
// 関数であり、処理系定義の
// NTBS(C言語形式の文字列)
// を返却します。
}
}
// ------------------------------------
《その194》 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クラスのオブジェクトを直接インスタンス化することはできません( ★1.)。
( type_info オブジェクトの生成は、typeid 演算子によってのみ可能です。)
・ 代入演算子「 = 」も private です。したがって、type_infoオブジェクトのコピーや代入を行うことはできません( ★2.)。
// ------------------------------------
#include <typeinfo>
#include <iostream>
int main() {
std::cout << typeid(int).name() << '\n';
// const type_info obj1 = typeid(int); // エラー ★1.
const type_info& ref1 = typeid(double);
std::cout << ref1.name() << '\n';
const type_info& ref2 = typeid(unsigned);
std::cout << ref2.name() << '\n';
const type_info* ptr = &typeid(double);
std::cout << ptr->name() << "\n\n";
// ref1 = ref2; // エラー ★2.
std::cout << std::boolalpha
<< (typeid(int) == typeid(5)) << '\n';
// operator==
std::cout << (typeid(int) != typeid(5)) << '\n';
// operator!=
}
// ------------------------------------
《その193》 typeid演算子
typeid演算子
typeid演算子は、多相的オブジェクトのように、実行時に型が決定するような場合、その実行時型情報 RTTI(Run-Time Type Information)を取得できる演算子です。
多相的クラス型のオブジェクトを typeid演算子のオペランドに与えると、実行時に決定された型を表現する const type_info型クラスオブジェクトへの参照が返されます。
例えば、多相的クラスオブジェクト x が実行時において Bbb型であるような場合、
std::cout << typeid(x).name(); // ★
と記述した場合には、
「 class Bbb 」 と出力されます。
★の name() は、type_infoクラスのメンバ関数です。
typeid(x)
で、typeid演算子のオペランドに x を与えています。すると、実行時に決定された型 Bbb を表現する type_infoクラスオブジェクトへの参照が返されます。
したがって、
std::cout << typeid(x).name();
は、例えば、
const type_info& ref = typeid(x);
std::cout << ref.name() << '\n';
あるいは、
const type_info* ptr = &typeid(x);
std::cout << ptr->name();
と同じ意味です。
// ------------------------------------
#include <iostream>
class Aaa {
virtual void f() const { };
};
class Bbb : public Aaa {
void f() const { };
};
void func(Aaa& x);
int main() {
Bbb obj_b;
Aaa& ref = obj_b;
func(obj_b);
}
void func(Aaa& x) {
std::cout << typeid(x).name() << '\n';
const type_info& ref = typeid(x);
std::cout << ref.name() << '\n';
const type_info* ptr = &typeid(x);
std::cout << ptr->name() << '\n';
}
// ------------------------------------