C ++类型转换:使用显式转换的好处?

时间:2010-06-24 07:23:52

标签: c++ casting

在c ++中使用这些运算符而不是隐式转换有什么好处?

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

我们应该在哪种情况下使用它们?它们在OOP中很少使用是真的吗?

6 个答案:

答案 0 :(得分:7)

从您提供的强制转换列表中,唯一有意义的用于构建隐式强制转换的是static_cast。

dynamic_cast用于将超类向下转换为其子类。这不可能隐式发生,实际上在OOP中并不罕见。 static_cast也可以在这样的演员阵容中使用,但它更危险,因为它不会在运行时检查向下转换是否有效。

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

答案 1 :(得分:3)

正如所有其他隐含的东西一样,它可能会隐藏开发人员/审阅者没有想到的逻辑,掩盖错误。

答案 2 :(得分:2)

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

Dynamic_cast可用于使用多态转换'upstream'。所以,如果你有这样的结构;

基地 - &gt;派生A

基地 - &gt;派生B

你可以做dynamic_cast(b); (b是指向Base的指针,但实际上是Derived_B);

如果它不是Derived_B类,则会返回0而不是转换后的指针。

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

reinterpret_cast只是改变了类型标签,启用了时髦的C风格FX(或称为'type-punning',通常称之为),对协议/低级工作很有用,但应该谨慎使用。

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

答案 3 :(得分:2)

对于一个非常简短的回答,这些演员表的好处是它们执行特定的功能,使代码具有描述性。 C风格的演员阵容非常强大,可以让你摆脱各种各样的错误。那些习惯于C的人可能会抱怨演员阵容很难写出来。这实际上被其他人认为是一件好事:它不鼓励程序员在他们的代码中撒上强制转换,这是代码有问题的一个非常明显的标志。最后,通过文本搜索很容易找到它们。

答案 4 :(得分:1)

使用C ++强制转换而不是C风格强制转换的一个好处是它们易于搜索。他们还分离了C型演员的不同应用,使气味易于识别。

例如,用于reinterpret_cast的grep可以很容易地找到许多潜在的问题和糟糕的设计,而正确识别C风格的强制转换的正则表达式则需要进一步检查以识别坏的角色。

如果需要强制转换,我总是会使用C ++强制转换而不是C风格的强制转换。

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

答案 5 :(得分:0)

只想添加一个使用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 )
{
}

这些是定义:

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
}
相关问题