C++;类型转换:使用显式转换的好处? 使用这些运算符代替C++中的隐式转换有什么好处?

C++;类型转换:使用显式转换的好处? 使用这些运算符代替C++中的隐式转换有什么好处?,c++,casting,C++,Casting,dynamic_cast <new_type> (expression) reinterpret_cast <new_type> (expression) static_cast <new_type> (expression) dynamic\u cast(表达式) 重新解释演员阵容(表达) 静态转换(表达式) 为什么,在哪里,在什么情况下我们应该使用它们?它们真的很少在OOP中使用吗?就像所有其他隐式转换一样,它可能隐藏了开发人员/审阅者没有想到的逻辑

dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression) 
dynamic\u cast(表达式)
重新解释演员阵容(表达)
静态转换(表达式)

为什么,在哪里,在什么情况下我们应该使用它们?它们真的很少在OOP中使用吗?

就像所有其他隐式转换一样,它可能隐藏了开发人员/审阅者没有想到的逻辑,掩盖了错误。

从您提供的转换列表中,用于支持隐式转换的唯一有意义的是静态转换

dynamic_cast用于将超类向下转换为其子类。这不能隐式发生,实际上在OOP中并不罕见。静态强制转换也可以用于此类强制转换,但它更危险,因为它在运行时不会检查向下强制转换是否有效


最后一个演员,reinterpret_cast,应该非常小心地使用,因为它是所有演员中最危险的。基本上,你可以用它将任何东西转换成任何东西,但作为程序员,你必须确保这种转换在语义上是有意义的,因为你基本上通过执行这种转换来关闭类型检查。

一般来说,我看到这些类型的转换出现在代码中,当一些东西不再构建时,可能是因为我们已经开始使用一个新的编译器,它对隐式转换更严格,所以这就是隐式转换的关键“好处”。显然,在这种情况下正确的做法是以其他方式更改代码

动态_cast可用于铸造具有多态性的“上游”。所以如果你有这样一个结构

基础->派生A

基础->派生B

你可以做动态演员(b);(b是指向基的指针,但实际上是派生的_b)

如果它不是派生类,则返回的将是0,而不是转换后的指针

这比静态转换慢得多,因为检查是在运行时而不是编译时完成的,但预期用途不同

reinterpret_cast只是更改了类型标签,启用了时髦的C风格的FX(或者通常称为“类型双关”),这对协议/低级工作很有用,但应该谨慎使用


通常,代码中的大量强制转换表示您的代码设计有问题。

只想添加一个使用reinterpret_cast的示例。假设一个库给你一个指向原始网络数据包的指针。要理解数据结构,可以使用结构,然后将指针强制转换到这些结构。请注意,编译器无法验证您是在做一些合理的事情,还是只是在内存中读取不应该读取的内容。在现实生活中,您应该首先检查数据包的大小,以确定它足够大,可以容纳您的结构

在下面的代码中,IPfragment构造函数获取一个数据包,然后将该指针强制转换为合理的内容。我添加了以下定义

如果有人仍然认为使用reinterpret_cast是不合理的,我很高兴在这里讨论一种更好的方法

IPfragment::IPfragment( const byte* const pkt_data ) :
    ethernetHeader( reinterpret_cast< const EthernetHeader* >( pkt_data                    )  )
  , ipHeader      ( reinterpret_cast< const IPheader*       >( pkt_data + ETHER_HEADER_LEN )  )
  , payload       ( reinterpret_cast< const byte*           >( ipHeader                    )
                                                             + ( ipHeader->ver_hl & 0x0f ) *4 )
{
}

<>使用C++的转换而不是C样式的转换的好处之一是它们很容易搜索。他们还分离出C型铸型的不同应用,使气味易于识别

例如,reinterpret_cast的grep可以很容易地发现许多潜在问题和糟糕的设计,而正确识别C样式转换的正则表达式需要进一步检查以识别糟糕的转换

如果需要强制转换,我将总是使用C++的转换和从不使用C样式的转换。p>


参见C++编码标准,萨特和Alexandrescu,第95项。

< P>一个非常简短的答案,这些转换的好处是它们执行特定的函数,使代码具有描述性。C风格的演员阵容是全能的,可以让你摆脱各种各样的错误。那些习惯使用C的人可能会抱怨说,这些演员阵容很难写出。这实际上被其他人认为是一件好事:它阻止程序员在他们的代码上散布强制类型转换,这是问题代码的一个非常明显的迹象。最后,通过文本搜索很容易找到它们。

Duplicates。
typedef uint8_t  byte  ;
typedef uint16_t word  ;
typedef uint32_t dword ;

#define ETHER_ADDR_LEN    6    // Ethernet addresses are 6 bytes
#define ETHER_HEADER_LEN  14   // Ethernet headers are 14 bytes
#define ETHER_TYPE_IP4    8 

struct EthernetHeader
{
   byte   etherDestHost[ETHER_ADDR_LEN];    // Destination host address
   byte   etherSrcHost [ETHER_ADDR_LEN];    // Source host address
   word   etherType;                        // IP? ARP? RARP? etc
};

/* 4 bytes IP address */
struct IPaddress
{
   byte byte1, byte2, byte3, byte4;
};

/* IPv4 header */
struct IPheader
{
   byte ver_hl          ;     // Version (4 bits) + Internet header length (4 bits)
   byte tos             ;     // Type of service
   word tlen            ;     // Total length
   word identification  ;     // Identification
   word flags_fo        ;     // Flags (3 bits) + Fragment offset (13 bits)
   byte ttl             ;     // Time to live
   byte proto           ;     // Protocol
   word crc             ;     // Header checksum
   IPaddress saddr      ;     // Source address
   IPaddress daddr      ;     // Destination address
   dword op_pad         ;     // Option + Padding
};

class IPfragment
{
  public:
    const IPheader*       const ipHeader;
    const EthernetHeader* const ethernetHeader;
    const byte*           const payload;

    IPfragment( const byte* const pkt_data );

    // rest of code omitted for brevity
}