我对c ++强制转换运算符有疑问。
假设您有一个班级Message
和几个子类:Message1
Message 2
等。
假设您有一个班级Event
以及不同的活动子类:Event 1
Event 2
在这两种情况下,我都可以将子类的类型与ID
(例如字段)区分开来
class Message {
....
int MessageID;
}
class Message1 : public Message {
//other fields;
}
class Message2 : public Message {
//other fields;
}
class Event {
int eventID;
}
class Event1 {
Message theMessage;
Message getMessage();
}
class Event2 {
Message theMessage;
}
我将实例Event1或Event2插入vector<Event>
在这种情况下,当我通过运营商提取事件时,虽然我确定你有一个Event1的实例,但使用static_cast
是正确的吗?例如:
Event theEvent = myVector.at(i);
Event1 *e1 = static_cast<Event1*>(&theEvent);
if(e1->getID() == xxx) {
Message2 *m2 = static_cast<Message2*>(&e1->getMessage());
}
我有一个问题:在最后一次演员之后,我没有看到作为Message2的实例信息(总是只有它的父类Message的那些) 在这种情况下,是否需要使用dynamic_cast?
答案 0 :(得分:3)
e1->getMessage()
返回Message类型的对象,而不是指针。所以你的数据将被切片。此外,您在此处投射指向临时的指针:
Message2 *m2 = static_cast<Message2*>(&e1->getMessage());
如果返回指针,则可以执行此操作。
Message * getMessage() { return &theMessage; }
static_cast
是将基指针强制转换为派生指针的正确方法,无需任何运行时检查。这样做的“更安全”的方法是使用dynamic_cast运算符,因为它会在将派生的内容转换为基指针或引用时执行运行时检查。 (我想如果我告诉你坚持static_cast
以避免那些检查,如果你有自己的那种证明是防止故障的话,那么我将在这里被石头打死。))
最好的方式(在我看来)是基类中适当的虚拟接口设计。您可以避免从基础转换为以这种方式派生。
此外,如果您使用Event
,则会对所有vector<Event>
进行切片。您只能使用vector<Event*>
来获取派生对象的集合,因为Base指针可能指向派生对象,但Base对象无法保存派生数据。 (您的向量中的所有派生Event
将会遗漏theMessage
,并且只有Event
中包含的数据。)
答案 1 :(得分:3)
通常,当您有派生类时,您应该使用虚函数。
在您的示例中,也许消息中的“内容”可以通过虚函数获得。
这个演员:
Event1 *e1 = static_cast<Event1*>(&theEvent);
不起作用。 theEvent
比Event1
小Message
- 这意味着您从中获取的任何消息都将是“随机垃圾”,因为您只有Event
第一名。
如果你想在你的事件数组中存储“任何类型的事件”,那么你需要存储指向Event
类型的指针,否则你肯定会遇到上面的切片问题。
答案 2 :(得分:1)
你提出的想法完全没有希望。您可以按结构和向量中的值存储所有基类。这意味着它们将完全是基类类型,而不是任何派生类型。因此,铸造对你没什么帮助。
您必须了解如何在集合或结构中存储多态对象。 (基本上通过某种指示,正确地解决了所有权问题)。
解决了存储问题之后,您可以回来查看存储问题 - 比较容易。