Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Октябрь 29, 2012, 16:08



Название: Привести член к классу
Отправлено: Igors от Октябрь 29, 2012, 16:08
Добрый день

Есть структурка
Код
C++ (Qt)
class CMyContext {
...
CMyPixel mPixel;
};
 
void DoSomething( CMyPixel * pix );
 
В какой-то момент внутри ф-ции DoSomething я узнаю что CPixel не какой-нибудь, а именно член класса CMyContext (исходя из др данных задачи). Как мне теперь заполучить указатель на CMyContext ?

Спасибо


Название: Re: Привести член к классу
Отправлено: Serr500 от Октябрь 29, 2012, 16:18
1) Поле parent в CMyPixel.
2) Какой-нибудь общий/глобальный массив вида (CMyPixel, CMyContext).


Название: Re: Привести член к классу
Отправлено: Serr500 от Октябрь 29, 2012, 16:20
3) А вот похитрее. Смещение mPixel в структуре известно. CMyContext можно получить как pix - offset(mPixel).


Название: Re: Привести член к классу
Отправлено: Igors от Октябрь 29, 2012, 16:45
3) А вот похитрее. Смещение mPixel в структуре известно. CMyContext можно получить как pix - offset(mPixel).
Ну да, так ведь это же "С приведение" и все такое - тут же все грамотные, заклюют :) Может есть козырный ++ способ ?


Название: Re: Привести член к классу
Отправлено: Akon от Октябрь 29, 2012, 19:33
Ну вот с т.з. DoSomething зачем ей знать, что переданный объект член чего то там. Поэтому, либо передавать содержащий объкут, либо сделать двунаправленнуя связь, т.е. parent.

Цитировать
3) А вот похитрее. Смещение mPixel в структуре известно. CMyContext можно получить как pix - offset(mPixel).
Это только как временный хак.


Название: Re: Привести член к классу
Отправлено: Igors от Октябрь 29, 2012, 20:17
Ну вот с т.з. DoSomething зачем ей знать, что переданный объект член чего то там. Поэтому, либо передавать содержащий объкут, либо сделать двунаправленнуя связь, т.е. parent.
А кто приводил пример кросс-приведения в случае множественного наследования? Та можно сказать "рекомендовал"  :) А тут членство вместо наследования - частая альтернатива.

Передача содержащего - явно навязанный параметр, который придется совать и совать "сверху" пока дело дойдет до DoSomething которая на самом низком уровне. Делать парента - также искусственно, что это за парент если его не назначают? Да и ничем оно не чище - после первого же копирования.

3) CMyContext можно получить как pix - offset(mPixel).
Кстати откуда взять offset и вообще как это приличнее записать?


Название: Re: Привести член к классу
Отправлено: Akon от Октябрь 29, 2012, 23:07
Цитировать
А кто приводил пример кросс-приведения в случае множественного наследования? Та можно сказать "рекомендовал"   А тут членство вместо наследования - частая альтернатива.
:) Согласен. Но там это было от своего рода безысходности. Если бы поддерживалось моком множественное да и до кучи виртуальное наследование от QObject, проблемы бы не было. У вас же руки развязаны.  

Цитировать
Передача содержащего - явно навязанный параметр, который придется совать и совать "сверху" пока дело дойдет до DoSomething которая на самом низком уровне. Делать парента - также искусственно, что это за парент если его не назначают? Да и ничем оно не чище - после первого же копирования.
Есть CMyContext и CMyPixel. Вы можете:
1. Передавать CMyContext и оставить однонапраленную связь CMyContext -> CMyPixel.
2. Передавать CMyPixel и сделать двунапраленную связь (парент) CMyContext <-> CMyPixel. Тут же получаете все проблемы двунаправленных ассоциаций. Я так понимаю, у вас классы-значения и всякие там ссылки (паренты) здесь не уместны.
3. Расширить функцию: void DoSomething(CMyContext*,  CMyPixel *); Недостаток в том, что можно подать пиксел не из того контекста. Достоинство - не нужно вводить связь между классами. Я довольно часто пользуюсь этив вариантом.

Цитировать
Кстати откуда взять offset и вообще как это приличнее записать?
Когда размер указалеля на член == sizeof(void*), то как-т так:
Код:
void DoSomething(CMyPixel *)
{
union X {
void* offset;
CMyPixel* CMyContext::* pointer;
};

X x;
x.pointer = &CMyContext::mPixel;  // далее юзайте x.offset

    ...
}
Если размер указалеля на член > sizeof(void*) (например, при виртуальном наследовании), то нужно в нем копаться и знать его формат, т.е. будут compiler-specific actions. Вообщем, не стоит хачить :)


Название: Re: Привести член к классу
Отправлено: Serr500 от Октябрь 30, 2012, 08:04
Ну да, так ведь это же "С приведение" и все такое - тут же все грамотные, заклюют :) Может есть козырный ++ способ ?
Нехай клевещут! клюют. Козырных способов я не вижу (что, впрочем, не означает, что из нет ;) )

размер указалеля на член > sizeof(void*)
Приведите примерчик.


Название: Re: Привести член к классу
Отправлено: Syveren от Октябрь 30, 2012, 09:46
Цитировать
Кстати откуда взять offset и вообще как это приличнее записать?
#include  <stddef.h>
Код
C++ (Qt)
/* Offset of member MEMBER in a struct of type TYPE. */
#ifndef __cplusplus
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#else
/* The cast to "char &" below avoids problems with user-defined
   "operator &", which can appear in a POD type.  */

#define offsetof(TYPE, MEMBER)                  \
  (__offsetof__ (reinterpret_cast <size_t>          \
                 (&reinterpret_cast <const volatile char &> \
                  (static_cast<TYPE *> (0)->MEMBER))))
#endif /* C++ */

По мне так самый правильный способ передавать CMyContext. А уже внутри выуживать его элемент.


Название: Re: Привести член к классу
Отправлено: Igors от Октябрь 30, 2012, 12:05
Я сделал так
Код
C++ (Qt)
void DoSomething( CMyPixel * pix )
{
CMyContext * ctx = 0;
ctx = (CMyContext *)((char *) pix - (size_t) &ctx->mPixel);
printf("pix = %p, ctx = %p\n", pix, ctx);
}
 
Что по существу ничем не отличается от варианта Syveren. Делать это макросом на мой взгляд неуместно, т.к. ни к чему поощрять использование такой конструкции.

Да, возможны перекрытые операторы (char *) и/или &. Но с др стороны
Код
C++ (Qt)
#define offsetof(TYPE, MEMBER)                  \
  (__offsetof__ (reinterpret_cast <size_t>          \
                 (&reinterpret_cast <const volatile char &> \
                  (static_cast<TYPE *> (0)->MEMBER))))
#endif /* C++ */
Вот после таких конструкций выражение "монструозный язык С++" уже не кажется глупым :) Да, это "более корректно", но это выносит мозг программиста заставляя вникать в дебри витиеватого синтаксиса.

Akon, попытки сделать это "просто корректным" введя доп поля (связи) разбиваются просто
Код
C++ (Qt)
CMyPixel::CMyPixel( const CMyPixel & )
{
//.. ???
}
 
Выясняется что CMyPixel не может решить что же с парентом, в результате каждое присвоение потребует внимания - такое лекарство хуже болезни


Название: Re: Привести член к классу
Отправлено: Akon от Октябрь 31, 2012, 21:13
Цитировать
static_cast<TYPE *> (0)->MEMBER
А до этого я сходу не допер :)

Цитировать
Akon, попытки сделать это "просто корректным" введя доп поля (связи) разбиваются просто
Код
C++ (Qt)
CMyPixel::CMyPixel( const CMyPixel & )
{
//.. ???
}
 
Выясняется что CMyPixel не может решить что же с парентом, в результате каждое присвоение потребует внимания - такое лекарство хуже болезни
Да, разумеется это большой напряг. Этот вариант, как правило, применяется для классов-сущностей (а они, как правило, с Q_DISABLE_COPY)