2013-03-14 5 views
4

В C++ У меня есть пакет базового класса, а затем много детей APIPacket, DataIOPacket и т. Д. Теперь я хочу сохранить входящий пакет, и поскольку я не знать тип хранить это в переменной:Функции вызова наследования C++ из дочернего элемента из переменной родительского класса

Packet packet; 
packet = DataIOPacket(); 

Но теперь DataIOPacket имеет функцию getAnalogData(); Я не могу сделать:

packet.getAnalogData(); 

Поскольку пакет не имеет этой функции. В java я думаю, что это возможно, так как фактический тип объекта, хранящегося в пакете, не теряется (это правильно?). Но в C++ мой DataIOPacket сужается в Packed и теряет его функции, которые не были объявлены в пакете.

Вы можете сделать виртуальную функцию в пакете для каждой функции в каждом дочернем элементе. Но для меня это означало бы множество функций в пакете, которые в большинстве случаев не следует вызывать. Не использовать вызов getAnalogData() в APIPacket.

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

Вы можете что-то сделать с приведением типов в DataIOPacket и APIPacket, но это не похоже на чистое решение.

Возможно, библиотеки, которые решают мою проблему?

Rgds,

Рул

+1

[Соответствующий] (http://stackoverflow.com/q/15306367/1174378) –

+2

Я изменил пакет Packet(); 'на' Packed packet; 'так, чтобы он определял объект (а не прототип функции) , чтобы соответствовать его описанию. Это не устраняет непосредственную проблему: когда вы храните объект производного типа в качестве объекта «Packet», производный объект получает срез для объекта «Packet». 'packet' ** не ** - объект производного типа. Код должен хранить указатель или ссылку на «Пакет», а не на объект. –

ответ

4

Это возможно в Java и C++ тоже. вам нужно сделать dynamic_cast, чтобы проверить тип.

Packet* packet; 
packet = new DataIOPacket(); 

     DataIOPacket dio* = dynamic_cast<DataIOPacket*>(packet); 
      if (dio != 0) 
      { 
      dio->DoSomeChildMethodStuff(); 
      } 
+1

Что делает оператор '! -'? –

+5

Это как! =, Только лучше :). спасибо, я исправил свой ответ –

+0

Так что это совершенно типично? Как я не мог найти это .. Я спросил много разработчиков C++, и никто не дал мне этот ответ После поиска в Интернете я должен спросить, должен ли исходный пакет быть указателем? Потому что в моем примере DataIOPacket помещается в пакет, и я предполагаю, что он теперь принял размер пакета и выбросил все остальное. – Silver

1

в C++ мой DataIOPacket сужается в Packet и теряет это функции, которые не были объявлены в Packet

Это происходит потому, что вы назначаете объект типа DataIOPacket к объект типа Packet, результатом которого является этот объект нарезанный (см. What is object slicing?).

То, что вы на самом деле ищете способ, как вы могли бы узнать в время выполнения, является ли объект, который вы работаете с была создана в качестве экземпляра DataIOPacket. Другими словами, вы ищете Run-Time Type Identification (RTTI).

Чтобы избежать нарезки, вам необходимо иметь ссылку или указатель на объект. Тип этого объекта будет затем идентифицированы в время выполнения:

Packet* packet; 
packet = new DataIOPacket(); 

Теперь packet является указателем на объект типа DataIOPacket (время выполнения), но тип указателя Packet* (время компиляции).Чтобы вызвать метод, специфичный для класса DataIOPacket для этого объекта, компилятору необходимо знать, что этот указатель указывает на объект типа, который предоставляет этот метод. Правильный путь вниз литья указатель полиморфного типа с помощью dynamic_cast, который возвращает NULL в случае, если этот объект не может быть приведен к этому типу:

Packet* packet; 
packet = new DataIOPacket(); 
DataIOPacket* dataIOPacket = dynamic_cast<DataIOPacket*>(packet); 
if (dataIOPacket) 
    dataIOPacket->getAnalogData(); 

Заметим, что это также возможно с объектами с автоматической продолжительностью хранения:

DataIOPacket packet; 
Packet* pPacket = &packet; 

DataIOPacket* dataIOPacket = dynamic_cast<DataIOPacket*>(pPacket); 
if (dataIOPacket) 
    dataIOPacket->getAnalogData(); 

в этом случае типа packet является решающим фактором, который решает, будет ли dynamic_cast успешным или нет. Объект должен быть создан как экземпляр DataIOPacket, чтобы вызвать метод getAnalogData.

+0

Почему пакет должен быть объявлен в кучу? Достаточно ли ответа Пита Беккера? Создание пакета в указатель и определение пакета DataIOPacket в стеке? – Silver

+1

@RoelStorms: Извините за путаницу, в этом случае не имеет значения, находится ли объект в стеке или в куче. Я отредактировал свой ответ, чтобы все было ясно. – LihO

0

Хорошо, я понял, что некоторые люди предположили, что наличие динамического броска предполагает, что моя структура неправильная. Поэтому я собираюсь изменить то, что каждый тип пакетов получает свое собственное пространство для хранения. Я храню пакеты, в которых я их читаю, и затем они передаются в основной поток, который выполняет всю обработку. Действительно, имеет смысл, что вы сохраняете тип. Мой основной поток не хочет определять, какой тип пакетов имеет, поскольку он имеет другой способ обращения с разными пакетами. Если вам когда-нибудь понадобится поведение, которое я описал в своем вопросе, я думаю, что динамический бросок - это путь. Но прежде чем делать это, вы должны действительно спросить себя, не следует ли изменять структуру. И использование динамического приведения не будет работать на объектах, так как они подвергаются разрезанию. Он работает только с указателями.