C++強制型変換(dynamic_cast,static_cast,const_cast,reinterpret_cast)
22477 ワード
C++は、4つの新しい強制タイプ変換形式(通常、新しいスタイルまたはC++スタイルと呼ばれる強制変換):const_cast(expression)、dynamic_cast(expression)、 reinterpret_cast(expression)とstatic_cast(expression)は、それぞれ特定の目的に適用されます.
dynamic_cast
継承レベルに沿ってクラスのポインタと参照を上、下、および横に変換します.
構文
dynamic_cast < new_type > ( expression )
注意:dynamic_castは、親クラスcastを子クラスにするときに使用します.親には虚関数が必要です.たとえば、CBasicクラスのtest関数をvirtualと定義しないコードでは、コンパイラがエラーを報告します.error C 2683:dynamic_キャスト:「CBasic」はマルチステートタイプではありません
コンパイラの要件:dynamic_cast<>はRTTIテクノロジーを使用します.そのため、VCでは「実行時タイプ情報」というオプションを起動する必要がある.Net 2003ではデフォルトでオフになっています.
dynamic_cast例
#include
using namespace std;
class CBasic
{
public:
virtual int test(){return 0;} // virtual
};
class CDerived : public CBasic
{
public:
virtual int test(){ return 1;}
};
int main()
{
CBasic cBasic;
CDerived cDerived;
CBasic * pB1 = new CBasic;
CBasic * pB2 = new CDerived;
//dynamic cast failed, so pD1 is null.
CDerived * pD1 = dynamic_cast (pB1);
std::cout << "pD1 = " << pD1 << std::endl;
//dynamic cast succeeded, so pD2 points to CDerived object
CDerived * pD2 = dynamic_cast (pB2);
std::cout << "pD2 = " << pD2 << std::endl;
//dynamci cast failed, so throw an exception.
// CDerived & rD1 = dynamic_cast (*pB1);
//dynamic cast succeeded, so rD2 references to CDerived object.
CDerived & rD2 = dynamic_cast (*pB2);
return 0;
}
static_cast
暗黙的およびユーザー定義変換の組合せを使用してタイプ間で変換します.
構文
static_cast < new_type > ( expression )
static_castは、強制的にステルス変換(例えばnon-constオブジェクトをconstオブジェクトに変換し、intをdoubleに変換するなど)に使用することができ、このような変換の多くの逆変換(例えばvoid*ポインタをタイプポインタに変換し、ベースクラスポインタを派生クラスポインタに変換する)にも使用することができる.ただし、constオブジェクトをnon-constオブジェクト(const_castのみ)に変換することはできません.C-styleの変換に最も近いです.クラスに適用されるポインタは、子クラスタイプのポインタを親クラスタイプのポインタに変換できるようにする(これは有効な暗黙的な変換である)とともに、親を子に変換する逆の動作も実行できます.
static_cast例
#include
#include
struct B {
int m = 0;
void hello() const {
std::cout << "Hello world, this is B!
";
}
};
struct D : B {
void hello() const {
std::cout << "Hello world, this is D!
";
}
};
enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };
int main()
{
// 1:
int n = static_cast<int>(3.14);
std::cout << "n = " << n << '
';
std::vector<int> v = static_cast<std::vector<int>>(10);
std::cout << "v.size() = " << v.size() << '
';
// 2:
D d;
B& br = d; //
br.hello();
D& another_d = static_cast(br); //
another_d.hello();
// 3:
std::vector<int> v2 = static_cast<std::vector<int>&&>(v);
std::cout << "after move, v.size() = " << v.size() << '
';
// 4:
static_cast<void>(v2.size());
// 5.
void* nv = &n;
int* ni = static_cast<int*>(nv);
std::cout << "*ni = " << *ni << '
';
// 6.
D a[10];
B* dp = static_cast(a);
// 7. int float
E e = E::ONE;
int one = static_cast<int>(e);
std::cout << one << '
';
// 8. int ,
E e2 = static_cast(one);
EU eu = static_cast(e2);
// 9.
int D::*pm = &D::m;
std::cout << br.*static_cast<int B::*>(pm) << '
';
// 10. void*
void* voidp = &e;
std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}
実行結果
n = 3
v.size() = 10
Hello world, this is B!
Hello world, this is D!
after move, v.size() = 0
*ni = 3
1
0
const_cast
const_castは一般に、オブジェクトの定数を強制的に除去するために使用されます.それが唯一できるC++スタイルの強制的な転換です.この変換は、オブジェクトのconstプロパティを剥離します.つまり、定数を変更できます.
構文
const_cast < new_type > ( expression )
const_cast例
#include
struct type {
int i;
type(): i(3) {}
void f(int v) const
{
// this->i = v; // : this const
const_cast(this)->i = v; // const OK
}
};
class C
{
};
int main()
{
int i = 3; // i const
const int& rci = i;
const_cast<int&>(rci) = 4; // OK : i
std::cout << "i = " << i << '
';
type t; // const type t , t.f(4)
t.f(4);
std::cout << "type::i = " << t.i << '
';
const int j = 3; // j const
int* pj = const_cast<int*>(&j);
// *pj = 4; //
void (type::* pmf)(int) const = &type::f; //
// const_cast(pmf); // : const_cast
const C *a = new C;
C *b = const_cast(a);
}
実行結果
i = 4
type::i = 4
reinterpret_cast
static_とcastは違いますがconst_とcast類似、reinterpret_cast式は、整数とポインタの間で変換したり、ポインタがそのタイプに依存する不明なアーキテクチャを表す場合を除き、CPU命令にコンパイルされません.コンパイラがexpressionのビットシーケンス(オブジェクト表示)をnew_と見なすことを示すコンパイル時コマンドです.typeタイプのビットシーケンス.
構文
reinterpret_cast < new_type > ( expression )
reinterpret_castは、特に下位層の強制的な転換に用いられ、依存(すなわち、移植不可能)を実現する結果をもたらし、例えば、ポインタを整数に転換する.このような強制タイプは、下位コード以外では極めて珍しいはずです.操作結果は,1つのポインタから別のポインタへの単純なバイナリコピーにすぎない.タイプ間で指す内容は、タイプのチェックや変換は行われません.
reinterpret_cast例
#include
#include
#include
int f() { return 42; }
int main()
{
int i = 7;
//
std::uintptr_t v1 = reinterpret_cast<:uintptr_t>(&i); // static_cast
std::cout << "The value of &i is 0x" << std::hex << v1 << '
';
int* p1 = reinterpret_cast<int*>(v1);
assert(p1 == &i);
//
void(*fp1)() = reinterpret_cast<void(*)()>(f);
// fp1();
int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
std::cout << std::dec << fp2() << '
'; //
//
char* p2 = reinterpret_cast<char*>(&i);
if(p2[0] == '\x7')
std::cout << "This system is little-endian
";
else
std::cout << "This system is big-endian
";
//
reinterpret_castint&>(i) = 42;
std::cout << i << '
';
const int &const_iref = i;
// int &iref = reinterpret_cast(const_iref); // —— const
// const_cast : int &iref = const_cast(const_iref);
}
実行結果
The value of &i is 0x61fe84
42
This system is little-endian
42
dynamic_キャストとstatic_キャストの違い
C++でdynamic_キャストとstatic_castはいずれも変換に使用されるオペレータであり、両者の不合理な運用により、コンパイル期間に合法的なタイプの変換操作が実行期間においてもエラーを引き起こす可能性があり、変換操作がオブジェクトポインタや参照に関連する場合、エラーが発生しやすい.この二つにはどんな違いがありますか.
使用方法:
dynamic_castptr、static_castptr;
dynamic_castp、static_castp;
次に、単純なコードを使用して、変換に関するいくつかの知識点を説明します.1つのベースクラスポインタは明確な変換操作を経ずに、ベースクラスオブジェクトまたは派生クラスオブジェクトを指すことができます.逆に、派生クラスポインタがベースクラスオブジェクトを指すのは賢明ではありません.
class B
{
...
};
class D : public B
{
...
};
int main( )
{
D* p;
p = new B(); // error
p = static_cast(new B()); // ,
}
次のコードを見てください.
#include
using namespace std;
class B
{
public:
virtual void f() { cout<< "f()" <class D : public B
{
public:
void m(){cout<< "m()" <int main()
{
D* p = static_cast(new B);
p -> m(); // ...
return 0;
}
ここでp->m()コンパイルはパスでき、一部のコンパイラでエラーが発生しました.Pは実際にはBのオブジェクトを指しているが、Bにはメンバー関数mがないため、この変換は安全ではない(MinGW gcc-6.3.0では正しく動作し、出力:m()).
C++提供dynamic_castオペレータは、実行中に移行動作が安全かどうかを検出できます.dynamic_キャストとstatic_castには同じ文法がありますがdynamic_castはマルチステートタイプにのみ有効です.
#include
using namespace std;
class C
{
// C
};
class T : public C
{
};
int main( )
{
T* p = dynamic_cast(new C()); // error, , static_cast
return 0;
}
注意:dynamic_cast操作の正しい前提は、変換のソースタイプはマルチステートである必要がありますが、変換のターゲットタイプがマルチステートであるかどうかは関係ありません.<>で指定したdynamic_castの目的タイプはポインタまたは参照でなければなりません.正しい使い方を見てみましょう.
#include
using namespace std;
class B
{
public:
virtual void f() {cout << "f()" << endl;}
};
class D:public B
{
public:
void m() {cout << "m()" << endl;}
};
int main()
{
D* p = dynamic_cast(new B()); // , , B , NULL。 NULL。
B* b_p = new D();
cout << "dynamic_cast1
";
if (p)
{
p -> m();
}
else
{
cout << "Error
";
}
cout << "dynamic_cast2
";
p = dynamic_cast(b_p) ;
if (p)
{
p -> m();
}
else
{
cout << "Error
";
}
return 0;
}
リファレンス
[1] dynamic_キャストとstatic_castの違い[2]static_cast ,reinterpret_cast-夏雪冬