static_cast dynamic_cast const_cast reinterpret_cast总结对比

时间:2022-05-28 04:24:49

【本文链接】

http://www.cnblogs.com/hellogiser/p/static_cast-dynamic_cast-const_cast-reinterpret_cast.html

【分析】

旧式风格 vs C++风格

 C++ Code 
1
2
3
4
5
6
7
 
(new_type) expression   // c-style
new_type (expression)  // function-style

dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

【static_cast】

用于基本数据类型之间的转换,如把int转换成char,把int转换成enum,这种转换的安全性也要开发人员来保证。

 C++ Code 
1
2
3
4
5
6
7
8
 
// basic type cast
, B, C };
;
;
char c = static_cast<char>(ui);
int i = static_cast<int>(d);
int j = static_cast<int>(B);
double k = static_cast<double>(ui);

用于类层次结构中基类和子类之间指针或引用的转换。(非多态类型转换,没有virtual)

  • 进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
  • 进行下行转换(把基类指针或引用转换成子类表示)时,转换是合法的,但是由于没有动态类型检查,所以是不安全的。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/22
*/

#include "stdafx.h"
#include "iostream"
using namespace std;

class Base
{
public:
    Base(): n1() {}
    int n1;
};

class Derived: public Base
{
public:
    Derived(): n2() {}
    int n2;
};

void test_static_cast()
{
    Base *p = new Base();
    Derived *pb = static_cast<Derived *>(p);
    cout << pb->n1 << endl; // 0  ok
    cout << pb->n2 << endl; // -33686019   (not safe)
    delete p;
}

int main()
{
    test_static_cast();
    ;
}

【dynamic_cast 】

用法:dynamic_cast < type-id > ( expression )
该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;
如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

dynamic_cast主要用于具有Virtual函数类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。(多态类型转换,必须要有virtual)

  • 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
  • 在进行下行转换时,dynamic_cast具有类型检查的功能,并且要求基类具有virtual函数,比static_cast更安全。(如果指针能够不能够正确转换,返回NULL;如果引用不能正确转换,则抛出bad_cast异常)

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/22
*/

#include "stdafx.h"
#include "iostream"
using namespace std;

class Base
{
public:
    Base(): n1() {}
    virtual void fun()
    {
        cout << "base" << endl;
    }
    int n1;
};

class Derived: public Base
{
public:
    Derived(): n2() {}
    void fun()
    {
        cout << "derived" << endl;
    }
    int n2;
};

void test_static_cast()
{

}

void test_dynamic_cast()
{
    Base *b = new Base();
    Derived *d = new Derived();

Derived *pd;
    // dynamic-cast
    pd = dynamic_cast<Derived *>(b); // pd==null
    if (pd == NULL)
    {
        cout << "first null" << endl; // first null
    }
    else
    {
        cout << pd->n2 << endl;
        pd->fun();
    }

pd = dynamic_cast<Derived *>(d); // pd !=null
    if (pd == NULL)
    {
        cout << "second null" << endl;
    }
    else
    {
        cout << pd->n2 << endl; // 0
        pd->fun();          // derived
    }

delete d;
    delete b;
}

int main()
{
    //test_static_cast();
    test_dynamic_cast();
    ;
}
/*
first null
0
derived
*/

上述例子,如果改为static_cast,则结果如下

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/22
*/

#include "stdafx.h"
#include "iostream"
using namespace std;

class Base
{
public:
    Base(): n1() {}
    virtual void fun()
    {
        cout << "base" << endl;
    }
    int n1;
};

class Derived: public Base
{
public:
    Derived(): n2() {}
    void fun()
    {
        cout << "derived" << endl;
    }
    int n2;
};

void test_static_cast()
{
    Base *b = new Base();
    Derived *d = new Derived();

Derived *pd;
    // static-cast
    pd = static_cast<Derived *>(b); // pd!=null
    if (pd == NULL)
    {
        cout << "first null" << endl;
    }
    else
    {
        cout << pd->n2 << endl; //      not safe
        pd->fun();              //      not safe
    }

pd = static_cast<Derived *>(d); // pd !=null
    if (pd == NULL)
    {
        cout << "second null" << endl;
    }
    else
    {
        cout << pd->n2 << endl; // 0
        pd->fun();          // derived
    }

delete d;
    delete b;
}

int main()
{
    test_static_cast();
    ;
}
/*
-33686019
base
0
derived
*/

由此可以看出,对于将基类指针转换为派生类指针的下行转换:

  • static_cast由于不做类型检查,能够正常转换,但是转换后的指针pb指向的是一个不完整的Derived对象,访问Derived对象的成员变量,会出现随机值(-33686019),而访问虚函数fun调用的也是Base的。
  • dynamic_cast做类型检查,知道不能够正常转换,因此返回NULL。

【const_cast】

const_cast:用来消除const, volatile, __unaligned属性的转换。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/22
*/

#include "stdafx.h"
#include "iostream"
using namespace std;

void print (char *str)
{
    cout << str << '\n';
}

void test_const_cast_fun ()
{
    const char *c = "sample text";
    print ( const_cast<char *> (c) ); // const cast
}

class CCTest
{
public:
    void setNumber( int );
    void printNumber() const;
private:
    int number;
};

void CCTest::setNumber( int num )
{
    number = num;
}

void CCTest::printNumber() const
{
    cout << "Before: " << number << endl;
    const_cast<CCTest *>(this)->number--; // remove const
    cout << "After: " << number << endl;
}

void test_const_cast_class()
{
    CCTest X;
    X.setNumber();
    X.printNumber();
}

int main()
{
    test_const_cast_fun();
    test_const_cast_class();
    ;
}

/*
sample text
Before: 8
After: 7
*/

【reinterpret_cast】

字面意思:重新解释(类型的比特位)。能够在任何类型的指针之间进行转换,也允许将任何整数类型转换为任何指针类型以及反向转换。在所有的转换中最“危险”,一定要慎用。

来看一个具体的例子:将变量地址转换为一个整数,再由整数转换为对应的指针。

【代码】

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/22
*/

#include "stdafx.h"
#include "iostream"
#include <assert.h>
using namespace std;

// address---> integer value
void test_reinterpret_cast()
{
    ;
    cout << std::hex << &i << endl;
    // pointer to integer
    unsigned int address = reinterpret_cast<unsigned int>(&i); // static_cast is an error
    cout << std::hex << address << '\n';
    // integer to pointer
    int *p = reinterpret_cast<int *>(address);
    assert(p == &i);

/*
    int i         7
    int address  ABCD
    int *p       ABCD
    */
}

int main()
{
    test_reinterpret_cast();
    ;
}

在实际中的应用价值:根据地址计算唯一的Hash值。

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/9/22
*/

#include "stdafx.h"
#include "iostream"
using namespace std;

// Returns a hash code based on an address
unsigned short Hash( void *p )
{
    unsigned int val = reinterpret_cast<unsigned int>( p );
    ));
}

void test_reinterpret_cast()
{
    ];
    ; i++ )
        cout << Hash( a + i ) << endl;
}

int main()
{
    test_reinterpret_cast();
    ;
}

/*
63876
63992
63996
63984
63988
63976
63980
63968
63972
63960
63964
63952
63956
63944
63948
63936
63940
64056
64060
64048
*/

【参考】

http://www.cplusplus.com/doc/tutorial/typecasting/

http://*.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used

http://blog.csdn.net/callmeback/article/details/4040583

http://www.cnblogs.com/goodcandle/archive/2009/03/17/1413907.html

http://en.cppreference.com/w/cpp/language/reinterpret_cast