Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> cast для POD структур, Как выполнить безопасное приведение типа 
V
    Опции темы
ZVano
  Дата 2.9.2011, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: 1
Всего: 4



Есть несколько POD структур.
Одна из них базовая (IShape), остальные наследники (IShapeRectangle, IShapeSquare).
Создаем по экземпляру наследников и передаем их в процедуру ShapeDraw как указатель на объект базового типа.
В процедуре ShapeDraw нужно выполнить обратное преобразование - из базового IShape получить целевой IShapeRectangle либо IShapeSquare.
Идентификация реального типа наследника происходит по коду в IShape->Code который указывается вручную при заполненни данными реального объекта.

Но т.к. все структуры являются POD типом, к ним нельзя применить dynamic_cast, а явное приведение вида shapeType * myShape = (shapeType *) myIShape

Как надежно выполнить проверку и приведение типа?

Вот пример кода на liveworkspace.org
Код

#include <iostream>

const int C_SHAPE_RECTANGLE = 10;
const int C_SHAPE_SQUARE = 20;

struct IShape{
  int Id;
  int Code;
  int X; 
  int Y; 
};

struct IShapeRectangle : public IShape{
  int Width;
  int Height;
};

struct IShapeSquare : public IShape{
  int SideLen;
};

void ShapeDraw(IShape * shape){
   std::cout << "SHAPE::Id = "<< shape->Id <<"; Code= " << shape->Code << "; X = " << shape->X << "; Y = " << shape->Y << std::endl;
   switch(shape->Code){
     case C_SHAPE_RECTANGLE :{
       IShapeRectangle * shapeCustom = NULL;
       //shapeCustom = dynamic_cast<IShapeRectangle *>(shape);
      //source.cpp:26:59: error: cannot dynamic_cast 'shape' (of type 'struct IShape*') to type 'struct IShapeRectangle*' (source type is not polymorphic) 
      shapeCustom = (IShapeRectangle *)shape;
       std::cout << "Width = " << shapeCustom->Width << "; Height = " << shapeCustom->Height <<std::endl;
       break;
     }  
     case C_SHAPE_SQUARE :{
       IShapeSquare * shapeCustom = NULL;
      shapeCustom = (IShapeSquare *)shape;
       std::cout << "SideLen = " << shapeCustom->SideLen <<std::endl;
       break;
     }  
   }
}

int main(){
   IShapeRectangle shapeRectangle;
   shapeRectangle.Code = C_SHAPE_RECTANGLE;
   shapeRectangle.Id = 1;
   shapeRectangle.X = 133;
   shapeRectangle.Y = 150;
   shapeRectangle.Width = 100;
   shapeRectangle.Height = 50;

   IShapeSquare shapeSquare;
   shapeSquare.Code = C_SHAPE_SQUARE;
   shapeSquare.Id = 2;
   shapeSquare.X = 77;
   shapeSquare.Y = 88;
   shapeSquare.SideLen = 200;
  
   ShapeDraw(&shapeRectangle);
   ShapeDraw(&shapeSquare);

   shapeSquare.Code = C_SHAPE_RECTANGLE;//<<Присваиваем неверный код фигуры
   shapeSquare.Id = 3;
   ShapeDraw(&shapeSquare); //<<Передаем с неверным кодом. Последствия непредсказуемы.
};



Результат
Код

SHAPE::Id = 1; Code= 10; X = 133; Y = 150
Width = 100; Height = 50
SHAPE::Id = 2; Code= 20; X = 77; Y = 88
SideLen = 200
SHAPE::Id = 3; Code= 10; X = 77; Y = 88
Width = 200; Height = 1



Это сообщение отредактировал(а) ZVano - 2.9.2011, 13:10


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
boostcoder
Дата 2.9.2011, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(ZVano @  2.9.2011,  11:46 Найти цитируемый пост)
все структуры являются POD типом

я неPOD`ами их сделать нельзя?

Добавлено через 2 минуты и 4 секунды
Цитата(ZVano @  2.9.2011,  11:46 Найти цитируемый пост)
struct IShapeRectangle : public IShape

тут public не нужен. структуры по умолчанию наследуются публично.
PM WWW   Вверх
ZVano
Дата 2.9.2011, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: 1
Всего: 4



Цитата(boostcoder @  2.9.2011,  12:07 Найти цитируемый пост)
неPOD`ами их сделать нельзя?

Вроде нельзя, но не уверен на 100%.
Реальная задача - обмен данными между плагинами, а в 1м посте максимально упрощенный пример для иллюстрации проблеммы.

Есть Plugin1 и Plugin2. Это структуры от базового интерфейса IPlugin.
В IPlugin определен виртуальный метод 
Код

struct TPluginMessage {
  DWORD msgCode;
  IPlugin * pluginSender;
};

struct IPlugin {
  //...
  virtual DWORD IPlugin_MessageParse(TPluginMessage * message)=0;
 //...
}

Он обязан быть реализован во всех плагинах-наследниках и предназначен для прямой коммуникачии между плагинами.
Т.е. Plugin1 и Plugin2 обнозначно содержат метод IPlugin_MessageParse.
Но передать туда можно данные любого типа, производного от TPluginMessage.
*Например:
** Plugin1 и Plugin2 знают публичный интерфейс друг-друга. 
** Plugin1 хочет вызвать внутренне действие Plugin2 (допустим, нарисовать меню код - C_PLUGIN2_DRAW_PLUGIN_MENU).
**В Plugin2 объявляется публичная структура 
Код

struct TPlugin2Message_DrawPluginMenu : public TPluginMessage{
  TMenuData menuData;
}

*** Plugin1 подготавливает структуру с данными типа TPlugin2Message_DrawPluginMenu msgXXX
Указывает код C_PLUGIN2_DRAW_PLUGIN_MENU
Указывает menuData
*** Вызывает метод Plugin2->IPlugin_MessageParse(&msgXXX);
***Plugin2
**** читает из msgXXX->msgCode который == C_PLUGIN2_DRAW_PLUGIN_MENU
**** приводит msgXXX к типу TPlugin2Message_DrawPluginMenu
**** вызполняет генерацию меню


PS: Возможно, я использую неверный подход, но другого в голову не приходит.




--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
boostcoder
Дата 2.9.2011, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



из всего тобою описанного, я не вижу требования для IShape быть POD`ом.
PM WWW   Вверх
ZVano
Дата 2.9.2011, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: 1
Всего: 4



Цитата(boostcoder @  2.9.2011,  12:47 Найти цитируемый пост)
из всего тобою описанного, я не вижу требования для IShape быть POD`ом.

Если объявить TPluginMessage nPOD-ом то можно спокойно использовать такой интерфейсный файл из разных компиляторов c++.
Код

struct TPluginMessage {
  DWORD msgCode;
  IPlugin * pluginSender;
  TPluginMessage(){
    msgCode = -1;
  };
};


Но если потребуется сделать интервейсный файл для Delphi, то там тоже прийдется писать тело конструктора.
Для других языков то же самое.
А в идее было создать просто интерфейс без реализации, поэтому и использовал nPOD.


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
mes
Дата 2.9.2011, 14:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



при чем тут вообще Pod /неPod ?!  smile

Добавлено через 3 минуты
Цитата(ZVano @  2.9.2011,  10:46 Найти цитируемый пост)

struct IShapeRectangle : public IShape{
 

уже неPod

Цитата(ZVano @  2.9.2011,  10:46 Найти цитируемый пост)
Но т.к. все структуры являются POD типом, к ним нельзя применить dynamic_cast,

не по этому .. 

Цитата(ZVano @  2.9.2011,  10:46 Найти цитируемый пост)
, а явное приведение вида shapeType * myShape = (shapeType *) myIShape

а что ж  static_cast зыбываем ?!

Добавлено через 5 минут и 4 секунды
Цитата(ZVano @  2.9.2011,  10:46 Найти цитируемый пост)
  shapeSquare.Code = C_SHAPE_RECTANGLE;//<<Присваиваем неверный код фигуры
   shapeSquare.Id = 3;
   ShapeDraw(&shapeSquare); 

а какое это вообще имеет отношение к касту ?! 
это вопрос по проектированию..

Добавлено через 8 минут и 28 секунд
Цитата(ZVano @  2.9.2011,  11:43 Найти цитируемый пост)
. Это структуры от базового интерфейса IPlugin.... Реальная задача - обмен данными между плагинами

и с каких это пор к наследникам интерфейса "нeприменим" dynamic_cast ?

Добавлено через 9 минут и 13 секунд
Цитата(ZVano @  2.9.2011,  12:03 Найти цитируемый пост)

Но если потребуется сделать интервейсный файл для Delphi, то там тоже прийдется писать тело конструктора.
Для других языков то же самое.
А в идее было создать просто интерфейс без реализации, поэтому и использовал nPOD. 

 smile  smile  smile  smile 


--------------------
PM MAIL WWW   Вверх
mes
Дата 2.9.2011, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(mes @  2.9.2011,  13:40 Найти цитируемый пост)
Это структуры от базового интерфейса IPlugin.

перечитал еще раз.. не "от базового интерфейса" а просто структуры, в данном случае структуры-сообщения..

Добавлено через 1 минуту и 14 секунд
но написаноп все равно жутко... пострайтесь сформулировать вопрос ясно, не опираясь на термины значения которых не до конца понимаете.. 



--------------------
PM MAIL WWW   Вверх
ZVano
Дата 2.9.2011, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: 1
Всего: 4



Цитата(mes @  2.9.2011,  14:40 Найти цитируемый пост)
уже неPod

Действительно, ведь было наследование п.3.4.b. 

Цитата(mes @  2.9.2011,  14:40 Найти цитируемый пост)
не по этому .. 

А почему? Пишет же что IShape "source type is not polymorphic"

Цитата(mes @  2.9.2011,  14:40 Найти цитируемый пост)
а что ж  static_cast зыбываем ?!

Не помогает 
Нужно сделать так, чтобы приведение не выполнялось если тип неверен.

Цитата(mes @  2.9.2011,  14:40 Найти цитируемый пост)
и с каких это пор к наследникам интерфейса "нeприменим" dynamic_cast ?

Как тогда объяснить это http://liveworkspace.org/code/9a7d3e17b78f...320e651c3db6612
Код

struct aaa{
  void SayHello(void){
    std::cout << "Привет." << std::endl;
  };
};

struct IShape : aaa{
  int Id;
  int Code;
  int X; 
  int Y; 
  IShape(){
   Id = -1; 
  };
};

...
       shapeCustom = dynamic_cast<IShapeRectangle *>(shape);
       shapeCustom = dynamic_cast<IShapeSquare *>(shape);

...


Код

source.cpp: In function 'void ShapeDraw(IShape*)':
source.cpp:36:59: error: cannot dynamic_cast 'shape' (of type 'struct IShape*') to type 'struct IShapeRectangle*' (source type is not polymorphic)
source.cpp:50:56: error: cannot dynamic_cast 'shape' (of type 'struct IShape*') to type 'struct IShapeSquare*' (source type is not polymorphic)

Build finished with errors


Цитата(mes @  2.9.2011,  15:01 Найти цитируемый пост)
перечитал еще раз.. не "от базового интерфейса" а просто структуры, в данном случае структуры-сообщения..

Тему интерфейсов и плагинов  предлагаю покаместь отложить. Давайте решим основной вопрос, либо прийдем к выводу что он нерешаем.

Цитата(mes @  2.9.2011,  15:01 Найти цитируемый пост)
...пострайтесь сформулировать вопрос ясно...

Мне нужно в процедуре void ShapeDraw(IShape * shape) определить является ли shape экземпляром IShapeRectangle или нет.
 

Это сообщение отредактировал(а) ZVano - 2.9.2011, 16:36


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
mes
Дата 2.9.2011, 16:31 (ссылка) |   (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(ZVano @  2.9.2011,  15:15 Найти цитируемый пост)
"source type is not polymorphic"

полиморфизм и Pod не связанные по сути сущности..

Добавлено через 2 минуты и 53 секунды
Цитата(ZVano @  2.9.2011,  15:15 Найти цитируемый пост)
Нужно сделать так, чтобы приведение не выполнялось если тип неверен.

и откуда программа будет знать, что тип неверен ?!  как уже говорилось
Цитата(mes @  2.9.2011,  13:40 Найти цитируемый пост)
это вопрос по проектированию..


Добавлено через 5 минут и 34 секунды
Цитата(ZVano @  2.9.2011,  15:15 Найти цитируемый пост)
Тему интерфейсов и плагинов  предлагаю покаместь отложить. Давайте решим основной вопрос, либо прийдем к выводу что он нерешаем.

так плагины Вы сами впихнули, а чтоб решить основной вопрос, его нужно как минимум сформулировать.. 

если вопрос : какой каст угадает у неполиморфного типа правильность приведения  ? -  то  он не решаем smile

Добавлено через 9 минут и 13 секунд
Цитата(ZVano @  2.9.2011,  15:15 Найти цитируемый пост)
Мне нужно в процедуре void ShapeDraw(IShape * shape) определить является ли shape экземпляром IShapeRectangle или нет.

ассоцируйте тип с неким кодом и проверяйте его.. 



--------------------
PM MAIL WWW   Вверх
ZVano
Дата 2.9.2011, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: 1
Всего: 4



Цитата(mes @  2.9.2011,  16:31 Найти цитируемый пост)
если вопрос : какой каст угадает у неполиморфного типа правильность приведения  ? -  то  он не решаем

Да, вопрос именно в этом и состоял. Спасибо.

Цитата(mes @  2.9.2011,  16:31 Найти цитируемый пост)
ассоцируйте тип с неким кодом и проверяйте его..

В первом примере так и сделал. 
Но при таком подходе возможны ошибки в случае, когда код фигуры задан неверно. И отследить их будет трудно.

Как правильно решить эту проблемму? 
Как изменить классы  чтобы можно было применить "dynamic_cast" к "IShape *"? >> что почитать smile


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
mes
Дата 2.9.2011, 17:03 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(ZVano @  2.9.2011,  15:59 Найти цитируемый пост)
В первом примере так и сделал. 
Но при таком подходе возможны ошибки в случае, когда код фигуры задан неверно. И отследить их будет трудно.

Как правильно решить эту проблемму? 


избавиться от рассоглaсования между типом и кодом..  в простых случаях достаточно доверить установку значения конструктору/функции-создателю.. 


Цитата(ZVano @  2.9.2011,  15:59 Найти цитируемый пост)
Как изменить классы  чтобы можно было применить "dynamic_cast" к "IShape *"? >> что почитать  

добавить в базу виртуальные методы (можно обойтись только виртуальным деструктором)..

Это сообщение отредактировал(а) mes - 2.9.2011, 17:09


--------------------
PM MAIL WWW   Вверх
newbee
Дата 2.9.2011, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 3
Всего: 19



Как-то все сумбурно, почему нельзя использовать наследование и dynamic_cast я так и не поняла.

Если все возможные типы наследников заранее известны, можно сделать так:

Код

struct base{
 enum {s1,s2}type;
 ....
 union s{
  struct {...}s1;
  struct {...}s2;
 };
};


Нужно ассоциировать тип с элементом юниона и в рантайме можно будет определять, что за зверь используется.

Это сообщение отредактировал(а) newbee - 2.9.2011, 17:11


--------------------
You're face to face
With man who sold the world
PM   Вверх
mes
Дата 2.9.2011, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



*union в приведенном выше примере фактически нужен для безопасного копированния объекта независимо от типа содержимого..

Добавлено через 33 секунды
то есть задачу соответсвия типа значению не решает.. 


--------------------
PM MAIL WWW   Вверх
ZVano
Дата 2.9.2011, 17:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: 1
Всего: 4



Цитата(mes @  2.9.2011,  17:03 Найти цитируемый пост)
в простых случаях достаточно доверить установку значения конструктору.. 

Все гениальное просто.  smile  Спасибо огромное, за ответ +.

Вот результат
Код

#include <iostream>

const int C_SHAPE_RECTANGLE = 10;
const int C_SHAPE_SQUARE = 20;

struct IShape{
  int Id;
  int X; 
  int Y; 
  IShape(){
    fCode = -1;
  }
  int GetCode(){
    return fCode;
  };
protected:
  int fCode;
};

struct IShapeRectangle : public IShape{
  int Width;
  int Height;
  IShapeRectangle (){
    fCode = C_SHAPE_RECTANGLE;
  }
  
};

struct IShapeSquare : public IShape{
  int SideLen;
  IShapeSquare (){
    fCode = C_SHAPE_SQUARE;
  }
};

void ShapeDraw(IShape * shape){
   std::cout << "SHAPE::Id = "<< shape->Id <<"; Code= " << shape->GetCode() << "; X = " << shape->X << "; Y = " << shape->Y << std::endl;
   switch(shape->GetCode()){
     case C_SHAPE_RECTANGLE :{
       IShapeRectangle * shapeCustom = NULL;
       //shapeCustom = dynamic_cast<IShapeRectangle *>(shape);
      //source.cpp:26:59: error: cannot dynamic_cast 'shape' (of type 'struct IShape*') to type 'struct IShapeRectangle*' (source type is not polymorphic) 
      shapeCustom = (IShapeRectangle *)shape;
       std::cout << "Width = " << shapeCustom->Width << "; Height = " << shapeCustom->Height <<std::endl;
       break;
     }  
     case C_SHAPE_SQUARE :{
       IShapeSquare * shapeCustom = NULL;
      shapeCustom = (IShapeSquare *)shape;
       std::cout << "SideLen = " << shapeCustom->SideLen <<std::endl;
       break;
     }  
    default: 
       std::cout << "Извини, чувак, не распознал тип фигуры " << std::endl;
       break;
   }
}

int main(){
   IShapeRectangle shapeRectangle;
   shapeRectangle.Id = 1;
   shapeRectangle.X = 133;
   shapeRectangle.Y = 150;
   shapeRectangle.Width = 100;
   shapeRectangle.Height = 50;

   IShapeSquare shapeSquare;
   shapeSquare.Id = 2;
   shapeSquare.X = 77;
   shapeSquare.Y = 88;
   shapeSquare.SideLen = 200;
  
   ShapeDraw(&shapeRectangle);
   ShapeDraw(&shapeSquare);

   IShape shapeX;
   shapeX.Id = 3;
   shapeX.X = 999; 
   shapeX.Y = 999; 
   ShapeDraw(&shapeX); 
};


Код

SHAPE::Id = 1; Code= 10; X = 133; Y = 150
Width = 100; Height = 50
SHAPE::Id = 2; Code= 20; X = 77; Y = 88
SideLen = 200
SHAPE::Id = 3; Code= -1; X = 999; Y = 999
Извини, чувак, не распознал тип фигуры 



--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0710 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.