2013-06-23 4 views
1

У меня есть вопрос о операторах слияния C++.Операторы C++ и литья

Предположим, у вас есть класс Message и несколько подклассов: Message1Message 2 и т.д.

Предположим, у вас есть класс Event, а также различные подклассы события: Event 1Event 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; 
} 

вставить экземпляры Даже t1 или 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

Если вектор всегда содержит объекты типа 'Event1', создайте его как контейнер объектов Event1. В противном случае используйте виртуальные функции или 'dynamic_cast' –

ответ

3

e1->getMessage() возвращает объект типа Message, а не указатель. Поэтому ваши данные будут нарезаны. Кроме того, вы указали на временный указатель:

Message2 *m2 = static_cast<Message2*>(&e1->getMessage()); 

Вы можете сделать это, если вы вернете указатель.

Message * getMessage() { return &theMessage; } 

static_cast является правильным способом литья базовых указателей на производные указатели без каких-либо проверок во время выполнения. «Безопасный» способ сделать это - использовать динамический оператор, конечно, так как он выполнит проверку выполнения при литье производного на базовый указатель или ссылку. (Я думаю, что меня забьют до смерти здесь, если я скажу вам придерживаться static_cast, чтобы избежать этих проверок, если у вас есть свой, который является отказоустойчивым.;))

Лучший способ (на мой взгляд) будет правильным дизайном виртуального интерфейса в базовых классах. Вы можете избежать кастинга с базы, чтобы получить этот путь.

Кроме того, вы нарезаете все свои Event с, если используете vector<Event>. Вы можете использовать только vector<Event*>, чтобы иметь свою коллекцию производных объектов, поскольку указатель Base может указывать на производные объекты, но базовые объекты не могут содержать Derived Data. (Все полученные Event s в вашем векторе пропустит theMessage и только данные, содержащиеся в Event.)

+0

Poppycock! 'dynamic_cast' - это правильный способ сбрасывания полиморфных типов. Использование 'static_cast' в этом случае рискует неопределенным поведением. –

+0

Это зависит от способа определения типа вашего объекта. Если вы выполнили надежную проверку времени выполнения, почему вы хотите, чтобы компилятор включал в себя все проверки времени выполнения? Ваш собственный чек может выйти из строя или быть ошибочным, поэтому вы правы, безопаснее работать с dynamic_cast, но для меня является общим соображением по эффективности и безопасности (по крайней мере, при программировании приложений HPC). – Pixelchemist

+0

Возможно, это может быть решение? // контейнер указателей базового класса vector сарай; // динамически выделяем экземпляр Animal и добавляем его в контейнер barn.push_back (new Dog()); но я не могу использовать динамическую память ... так как «новый», как я могу это достичь? – Safari

3

Обычно, когда вы производные классы, вы должны использовать виртуальные функции.

В вашем примере, возможно, «контент» в сообщении может быть получен через виртуальную функцию.

Этот бросок:

Event1 *e1 = static_cast<Event1*>(&theEvent); 

не будет работать. theEvent меньше Event1 от Message - это означает, что любое сообщение, которое вы получите из него, будет «случайным мусором», потому что у вас только был Event.

Если вы хотите сохранить «любой тип события» в вашем массиве событий, вам необходимо сохранить указатели на тип Event, иначе вы определенно страдаете от проблемы разреза, которая у вас выше.

+0

Как вы думаете, я могу решить мою проблему? Можете ли вы предложить практическое решение или пример, который поможет мне понять? – Safari

+0

Поскольку вы на самом деле не описали то, что находится в разных типах сообщений, или как они используются вызывающим кодом, трудно быть конкретным. –

+0

В каждом подклассе сообщения есть еще несколько полей во всем остальном. Родительский класс имеет некоторые поля, общие для всех подклассов. – Safari

1

Ваша идея, как представлено, полностью безнадежна. Вы сохраняете все базовые классы по значению в структурах и векторе. Это означает, что они будут точно такими же типами базового класса, ни в одном из ваших производных. Таким образом, кастинг вам не поможет.

Вы должны прочитать о том, как хранить polymorphic объекты в коллекциях или структурах. (в основном через какие-то указатели, правильное распределение прав собственности).

После того, как вы решили проблему с хранилищем, вы можете вернуться к кастингу - это будет легко сравнить.

+0

Как вы думаете, я могу решить мою проблему? Можете ли вы предложить практическое решение или пример, который поможет мне понять? – Safari

 Смежные вопросы

  • Нет связанных вопросов^_^