在c ++中使用这些运算符而不是隐式转换有什么好处?
dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
我们应该在哪种情况下使用它们?它们在OOP中很少使用是真的吗?
答案 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
}