C++ 什么时候应该使用静态转换、动态转换、常量转换和重新解释转换?

C++ 什么时候应该使用静态转换、动态转换、常量转换和重新解释转换?,c++,pointers,casting,c++-faq,C++,Pointers,Casting,C++ Faq,以下各项的正确用途是什么: static\u cast dynamic\u cast const\u cast 重新解释演员阵容 C型铸造(类型)值 函数样式转换类型(值) 如何决定在哪些特定情况下使用哪种方法?是否回答了您的问题 我从未使用过重新解释cast,我想知道遇到需要它的案例是否意味着设计糟糕。在我的代码库中,dynamic\u cast被大量使用。与static\u cast的不同之处在于dynamic\u cast执行运行时检查,您想要的可能是(更安全的)也可能不是(更高的开销

以下各项的正确用途是什么:

  • static\u cast
  • dynamic\u cast
  • const\u cast
  • 重新解释演员阵容
  • C型铸造
    (类型)值
  • 函数样式转换
    类型(值)
如何决定在哪些特定情况下使用哪种方法?

是否回答了您的问题


我从未使用过
重新解释cast
,我想知道遇到需要它的案例是否意味着设计糟糕。在我的代码库中,
dynamic\u cast
被大量使用。与
static\u cast
的不同之处在于
dynamic\u cast
执行运行时检查,您想要的可能是(更安全的)也可能不是(更高的开销)(请参见)。

使用
dynamic\u cast
转换继承层次结构中的指针/引用

对普通类型转换使用
static\u cast

使用
reinterpret\u cast
对位模式进行低级重新解释。使用时要格外小心


使用
const\u cast
来丢弃
const/volatile
。避免这种情况,除非您使用的常量API不正确。

静态强制转换是您应该尝试使用的第一个强制转换。它可以在类型之间进行隐式转换(例如
int
float
,或指向
void*
)的指针),还可以调用显式转换函数(或隐式转换函数)。在许多情况下,显式地声明
static\u cast
是不必要的,但是需要注意的是
t(something)
语法相当于
(t)something
,应该避免(稍后将详细介绍)。然而,
T(某物,某物)
是安全的,并且保证调用构造函数

static\u cast
也可以通过继承层次结构进行强制转换。向上强制转换(朝向基类)时不需要它,但向下强制转换时,只要它不通过
virtual
继承强制转换,就可以使用它。但是,它不进行检查,将层次结构向下转换为实际上不是对象类型的类型是未定义的行为


const\u cast
可用于删除变量或将
const
添加到变量中;没有其他C++编译器能够删除它(甚至不<代码> RealTytCase)。需要注意的是,只有在原始变量为
const
时,修改以前的
const
值才是未定义的;如果使用它将
const
从对未使用
const
声明的内容的引用中移除,则它是安全的。例如,当基于
const
重载成员函数时,这可能很有用。它还可用于向对象添加
const
,例如调用成员函数重载

const_cast
也同样适用于
volatile
,尽管这不太常见


dynamic\u cast
专门用于处理多态性。您可以将指向任何多态类型的指针或引用强制转换为任何其他类类型(多态类型至少有一个声明或继承的虚拟函数)。你可以使用它,而不仅仅是向下抛投——你可以侧向抛投,甚至是向上抛投另一条链条。
dynamic_cast
将查找所需对象,并在可能的情况下返回该对象。如果不能,它将在指针的情况下返回
nullptr
,或者在引用的情况下抛出
std::bad_cast

尽管如此,
dynamic_cast
有一些限制。如果继承层次结构(即所谓的“可怕的钻石”)中有多个相同类型的对象,并且您没有使用
virtual
继承,那么它就不起作用。它也只能通过公共继承-它将始终无法通过
受保护
私有
继承。然而,这很少是一个问题,因为这种形式的继承很少


重新解释施法
是最危险的施法,应该非常谨慎地使用。它将一种类型直接转换为另一种类型-例如将值从一个指针转换为另一个指针,或者将指针存储在
int
中,或者其他各种讨厌的东西。在很大程度上,通过
reinterpret_cast
得到的唯一保证是,通常如果将结果转换回原始类型,则会得到完全相同的值(但如果中间类型小于原始类型,则不会)。有许多转换
重新解释\u cast
也无法完成。它主要用于特别奇怪的转换和位操作,如将原始数据流转换为实际数据,或将数据存储在指向对齐数据的指针的低位


C-style cast函数样式cast分别使用
(类型)对象
类型(对象)
进行强制转换,并且在功能上是等效的。它们被定义为以下成功的第一项:

  • const\u cast
  • static\u cast
    (尽管忽略访问限制)
  • static\u cast
    (见上文),然后
    const\u cast
  • 重新解释演员阵容
  • 重新解释cast
    ,然后
    const\u cast
因此,在某些情况下,它可以用作其他类型转换的替代品,但可能非常危险,因为它可以转化为一个
重新解释类型转换
,并且在需要显式转换时,应首选后者,除非您确定
static\u cast
将成功或
reinterpret\u cast
将失败。即使这样,也要考虑更长、更明确的选择。

OnEventData(void* pData) { ...... // pData is a void* pData, // EventData is a structure e.g. // typedef struct _EventData { // std::string id; // std:: string remote_id; // } EventData; // On Some Situation a void pointer *pData // has been static_casted as // EventData* pointer EventData *evtdata = static_cast<EventData*>(pData); ..... }

void DebugLog::OnMessage(Message *msg)
{
    static DebugMsgData *debug;
    static XYZMsgData *xyz;

    if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){
        // debug message
    }
    else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){
        // xyz message
    }
    else/* if( ... )*/{
        // ...
    }
}
// *Passwd declared as a const

const unsigned char *Passwd


// on some situation it require to remove its constness

const_cast<unsigned char*>(Passwd)
typedef unsigned short uint16;

// Read Bytes returns that 2 bytes got read. 

bool ByteBuffer::ReadUInt16(uint16& val) {
  return ReadBytes(reinterpret_cast<char*>(&val), 2);
}
#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    //static_cast<void**>(&pNetFwPolicy2) would give a compile error
    reinterpret_cast<void**>(&pNetFwPolicy2) );
#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
void* tmp = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    &tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);
int a=rand(); // Random number.

int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation.

int* pa2=static_cast<int*>(a); // Compiler error.
int* pa3=dynamic_cast<int*>(a); // Compiler error.

int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo.

*pa4=5; // Program crashes.
struct Foo{};
struct Bar{};

int main(int argc, char** argv)
{
    Foo* f = new Foo;

    Bar* b1 = f;                              // (1)
    Bar* b2 = static_cast<Bar*>(f);           // (2)
    Bar* b3 = dynamic_cast<Bar*>(f);          // (3)
    Bar* b4 = reinterpret_cast<Bar*>(f);      // (4)
    Bar* b5 = const_cast<Bar*>(f);            // (5)

    return 0;
}
#include <iostream>

struct B1 {
    B1(int int_in_b1) : int_in_b1(int_in_b1) {}
    virtual ~B1() {}
    void f0() {}
    virtual int f1() { return 1; }
    int int_in_b1;
};

struct B2 {
    B2(int int_in_b2) : int_in_b2(int_in_b2) {}
    virtual ~B2() {}
    virtual int f2() { return 2; }
    int int_in_b2;
};

struct D : public B1, public B2 {
    D(int int_in_b1, int int_in_b2, int int_in_d)
        : B1(int_in_b1), B2(int_in_b2), int_in_d(int_in_d) {}
    void d() {}
    int f2() { return 3; }
    int int_in_d;
};

int main() {
    B2 *b2s[2];
    B2 b2{11};
    D *dp;
    D d{1, 2, 3};

    // The memory layout must support the virtual method call use case.
    b2s[0] = &b2;
    // An upcast is an implicit static_cast<>().
    b2s[1] = &d;
    std::cout << "&d           " << &d           << std::endl;
    std::cout << "b2s[0]       " << b2s[0]       << std::endl;
    std::cout << "b2s[1]       " << b2s[1]       << std::endl;
    std::cout << "b2s[0]->f2() " << b2s[0]->f2() << std::endl;
    std::cout << "b2s[1]->f2() " << b2s[1]->f2() << std::endl;

    // Now for some downcasts.

    // Cannot be done implicitly
    // error: invalid conversion from ‘B2*’ to ‘D*’ [-fpermissive]
    // dp = (b2s[0]);

    // Undefined behaviour to an unrelated memory address because this is a B2, not D.
    dp = static_cast<D*>(b2s[0]);
    std::cout << "static_cast<D*>(b2s[0])            " << dp           << std::endl;
    std::cout << "static_cast<D*>(b2s[0])->int_in_d  " << dp->int_in_d << std::endl;

    // OK
    dp = static_cast<D*>(b2s[1]);
    std::cout << "static_cast<D*>(b2s[1])            " << dp           << std::endl;
    std::cout << "static_cast<D*>(b2s[1])->int_in_d  " << dp->int_in_d << std::endl;

    // Segfault because dp is nullptr.
    dp = dynamic_cast<D*>(b2s[0]);
    std::cout << "dynamic_cast<D*>(b2s[0])           " << dp           << std::endl;
    //std::cout << "dynamic_cast<D*>(b2s[0])->int_in_d " << dp->int_in_d << std::endl;

    // OK
    dp = dynamic_cast<D*>(b2s[1]);
    std::cout << "dynamic_cast<D*>(b2s[1])           " << dp           << std::endl;
    std::cout << "dynamic_cast<D*>(b2s[1])->int_in_d " << dp->int_in_d << std::endl;

    // Undefined behaviour to an unrelated memory address because this
    // did not calculate the offset to get from B2* to D*.
    dp = reinterpret_cast<D*>(b2s[1]);
    std::cout << "reinterpret_cast<D*>(b2s[1])           " << dp           << std::endl;
    std::cout << "reinterpret_cast<D*>(b2s[1])->int_in_d " << dp->int_in_d << std::endl;
}

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
setarch `uname -m` -R ./main.out
gdb -batch -ex "disassemble/rs main" main.out
&d           0x7fffffffc930
b2s[0]       0x7fffffffc920
b2s[1]       0x7fffffffc940
b2s[0]->f2() 2
b2s[1]->f2() 3
static_cast<D*>(b2s[0])            0x7fffffffc910
static_cast<D*>(b2s[0])->int_in_d  1
static_cast<D*>(b2s[1])            0x7fffffffc930
static_cast<D*>(b2s[1])->int_in_d  3
dynamic_cast<D*>(b2s[0])           0
dynamic_cast<D*>(b2s[1])           0x7fffffffc930
dynamic_cast<D*>(b2s[1])->int_in_d 3
reinterpret_cast<D*>(b2s[1])           0x7fffffffc940
reinterpret_cast<D*>(b2s[1])->int_in_d 32767
B1:
  +0: pointer to virtual method table of B1
  +4: value of int_in_b1
B2:
  +0: pointer to virtual method table of B2
  +4: value of int_in_b2
D:
  +0: pointer to virtual method table of D (for B1)
  +4: value of int_in_b1
  +8: pointer to virtual method table of D (for B2)
 +12: value of int_in_b2
 +16: value of int_in_d
b2s[1] = &d;
&d           0x7fffffffc930
b2s[1]       0x7fffffffc940
49          dp = static_cast<D*>(b2s[0]);
   0x0000000000000fc8 <+414>:   48 8b 45 d0     mov    -0x30(%rbp),%rax
   0x0000000000000fcc <+418>:   48 85 c0        test   %rax,%rax
   0x0000000000000fcf <+421>:   74 0a   je     0xfdb <main()+433>
   0x0000000000000fd1 <+423>:   48 8b 45 d0     mov    -0x30(%rbp),%rax
   0x0000000000000fd5 <+427>:   48 83 e8 10     sub    $0x10,%rax
   0x0000000000000fd9 <+431>:   eb 05   jmp    0xfe0 <main()+438>
   0x0000000000000fdb <+433>:   b8 00 00 00 00  mov    $0x0,%eax
   0x0000000000000fe0 <+438>:   48 89 45 98     mov    %rax,-0x68(%rbp)
59          dp = dynamic_cast<D*>(b2s[0]);
   0x00000000000010ec <+706>:   48 8b 45 d0     mov    -0x30(%rbp),%rax
   0x00000000000010f0 <+710>:   48 85 c0        test   %rax,%rax
   0x00000000000010f3 <+713>:   74 1d   je     0x1112 <main()+744>
   0x00000000000010f5 <+715>:   b9 10 00 00 00  mov    $0x10,%ecx
   0x00000000000010fa <+720>:   48 8d 15 f7 0b 20 00    lea    0x200bf7(%rip),%rdx        # 0x201cf8 <_ZTI1D>
   0x0000000000001101 <+727>:   48 8d 35 28 0c 20 00    lea    0x200c28(%rip),%rsi        # 0x201d30 <_ZTI2B2>
   0x0000000000001108 <+734>:   48 89 c7        mov    %rax,%rdi
   0x000000000000110b <+737>:   e8 c0 fb ff ff  callq  0xcd0 <__dynamic_cast@plt>
   0x0000000000001110 <+742>:   eb 05   jmp    0x1117 <main()+749>
   0x0000000000001112 <+744>:   b8 00 00 00 00  mov    $0x0,%eax
   0x0000000000001117 <+749>:   48 89 45 98     mov    %rax,-0x68(%rbp)
70          dp = reinterpret_cast<D*>(b2s[1]);
   0x00000000000011fa <+976>:   48 8b 45 d8     mov    -0x28(%rbp),%rax
   0x00000000000011fe <+980>:   48 89 45 98     mov    %rax,-0x68(%rbp)