Определить смещение члена в классе
От: Went  
Дата: 02.10.05 12:01
Оценка:
Возможно, уже обсуждалось, но в поиске не нашел.

Вопрос предельно прост: есть структура

struct TestStruct
{
  int a;
  int b;
};


Нужно определить смещение члена TestStruct::b относительно начала структуры, дабы выполнялось условие:

TestStruct ts;
ASSERT(&ts.b == &ts + member_shift<TestStruct, TestStruct::b>()) //синтаксис ф-ции member_shift приблизителен


Какова должна быть реализации функции member_shift?

Я вижу 3 варианта, но все с боками

1. Через указатель на переменную-член, который потом варварски приводится к int. Недостатки — возможные проблемы с множественным и проч. наследованием

2. Через взятия адреса переменной-члена класса через указатель на объект этого класса, равный 0. Недостаток — страшно как-то, особенно, если есть
виртуальное наследование...

3. Через инстанцирование объекта и взятие разницы адресов. Недостаток — а если нет конструктора по умолчанию или класс абстрактен?.

Подскажите пожайлуста, что лучше
Re: Определить смещение члена в классе
От: Сергей Мухин Россия  
Дата: 02.10.05 12:09
Оценка:
Здравствуйте, Went, Вы писали:

W>Возможно, уже обсуждалось, но в поиске не нашел.


W>Вопрос предельно прост: есть структура


W>Нужно определить смещение члена TestStruct::b относительно начала структуры, дабы выполнялось условие:



#ifndef FIELDOFFSET
#define FIELDOFFSET(type, field) (reinterpret_cast<size_t>(&(((type *)0)->field)))
#endif
---
С уважением,
Сергей Мухин
Re[2]: Определить смещение члена в классе
От: Went  
Дата: 02.10.05 13:25
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>#ifndef FIELDOFFSET

СМ>#define FIELDOFFSET(type, field) (reinterpret_cast<size_t>(&(((type *)0)->field)))
СМ>#endif

Как я уже говорил, с таким вариантом не работает:

struct X
{
  virtual void f() {}
  
  int x_value;
};

struct Y : public virtual X
{
};

struct Z : public virtual X
{
};

struct W : public Z, public Y
{
  int w_value;
};

void test()
{
  W* w = NULL;
  void* det_w = &w->w_value; //тут какая-то билеберда
  void* det_x = &w->x_value; //а тута Access violation reading location 0x00000000.
}


Возможно, я не уловил суть Вашего предложения, тогда поправьте.
Re[3]: Определить смещение члена в классе
От: pavel_turbin  
Дата: 02.10.05 14:16
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Сергей Мухин, Вы писали:


СМ>>#ifndef FIELDOFFSET

СМ>>#define FIELDOFFSET(type, field) (reinterpret_cast<size_t>(&(((type *)0)->field)))
СМ>>#endif

W>Как я уже говорил, с таким вариантом не работает:


W>
W>struct X
W>{
W>  virtual void f() {}
  
W>  int x_value;
W>};

W>struct Y : public virtual X
W>{
W>};

W>struct Z : public virtual X
W>{
W>};

W>struct W : public Z, public Y
W>{
W>  int w_value;
W>};

W>void test()
W>{
W>  W* w = NULL;
W>  void* det_w = &w->w_value; //тут какая-то билеберда
W>  void* det_x = &w->x_value; //а тута Access violation reading location 0x00000000.
W>}
W>


W>Возможно, я не уловил суть Вашего предложения, тогда поправьте.



должно работать
FIELDOFFSET(W, w_value);
Re: Определить смещение члена в классе
От: Анатолий Широков СССР  
Дата: 02.10.05 14:24
Оценка:
W>Нужно определить смещение члена TestStruct::b относительно начала структуры, дабы выполнялось условие:

W>
W>TestStruct ts;
W>ASSERT(&ts.b == &ts + member_shift<TestStruct, TestStruct::b>()) //синтаксис ф-ции member_shift приблизителен
W>


W>Какова должна быть реализации функции member_shift?


W>Подскажите пожайлуста, что лучше


То есть Вам нужен аналог offsetof? А чем сам offsetof не устраивает?
Re[4]: Определить смещение члена в классе
От: Went  
Дата: 02.10.05 14:27
Оценка:
Здравствуйте, pavel_turbin, Вы писали:

_>должно работать

_>FIELDOFFSET(W, w_value);

Это работает, видать, ошибся где-то.

А вот это:

FIELDOFFSET(W, x_value);


Не работает, ибо, по-моему, не должно работать в принципе.

Насколько я понимаю, причина тута в том, что в объекте — виртуальном наследнике класса X, по определенному смещению от начала объекта должно находиться смещение this объекта Х от начала этого объекта. То есть для того, чтобы привести экземпляр W к X нужно полезть в память, а там нас ждет билеберда, а не смещение.

Возможно, каждый компилятор сам решает как ему располагать данные объекта, но ма родном VC7.1 у меня не работает.
Re[2]: Определить смещение члена в классе
От: Went  
Дата: 02.10.05 14:28
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>То есть Вам нужен аналог offsetof? А чем сам offsetof не устраивает?


Наверняка, устраивает Это бустовская штука?
Re[3]: Определить смещение члена в классе
От: Анатолий Широков СССР  
Дата: 02.10.05 14:31
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Анатолий Широков, Вы писали:


АШ>>То есть Вам нужен аналог offsetof? А чем сам offsetof не устраивает?


W>Наверняка, устраивает Это бустовская штука?


Нет, это ANSI-шная штука из <stddef.h>, но с виртуальным наследованием она, думаю, разобраться не сможет.
Re[4]: Определить смещение члена в классе
От: Went  
Дата: 02.10.05 14:37
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Нет, это ANSI-шная штука из <stddef.h>, но с виртуальным наследованием она, думаю, разобраться не сможет.


Да, не разобралась
Re[5]: Определить смещение члена в классе
От: Анатолий Широков СССР  
Дата: 02.10.05 14:39
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Анатолий Широков, Вы писали:


АШ>>Нет, это ANSI-шная штука из <stddef.h>, но с виртуальным наследованием она, думаю, разобраться не сможет.


W>Да, не разобралась


Хорошо, а если бы разобралась, то чтобы это Вам дало?
Re: Определить смещение члена в классе
От: Went  
Дата: 02.10.05 14:43
Оценка:
Вариант с указателем на переменную-член тоже отпадает — работает только в тривиальных случаях
Re[6]: Определить смещение члена в классе
От: Went  
Дата: 02.10.05 14:45
Оценка:
АШ>Хорошо, а если бы разобралась, то чтобы это Вам дало?

Каюсь, вопрос, скорее, академический
Re: Определить смещение члена в классе
От: Павел Кузнецов  
Дата: 02.10.05 15:20
Оценка:
Went,

> Вопрос предельно прост: есть структура

>
> struct TestStruct
> {
>   int a;
>   int b;
> };
>

> Нужно определить смещение члена TestStruct::b относительно начала структуры, дабы выполнялось условие:

Для этого случая (POD-класс-тип), как уже упоминалось, будет работать offsetof.

> 1. Через указатель на переменную-член, который потом варварски приводится к int. Недостатки — возможные проблемы с множественным и проч. наследованием


Не возможные, а вполне реальные.

> 2. Через взятия адреса переменной-члена класса через указатель на объект этого класса, равный 0. Недостаток — страшно как-то, особенно, если есть виртуальное наследование...


В случае наличия виртуального наследования в общем случае смещение получить невозможно, т.к. оно зависит от динамического типа объекта.
#include <iostream>

struct A
{
   int a;
};

struct B : virtual A
{
   int b;
};

struct C : B
{
   int c;
};

void ba(B& b)
{
   std::cout << (char*)&b.a - (char*)&b << std::endl;
}

int main()
{
   B b;
   ba(b);

   C c;
   B& bc = c;
   ba(bc);
}

VC++8:
8
12


> Подскажите пожайлуста, что лучше


Лучше рассказать, в чем заключается решаемая проблема, и, может быть, кто-нибудь сможет подсказать другое решение начальной задачи.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Определить смещение члена в классе
От: Went  
Дата: 03.10.05 06:55
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Не возможные, а вполне реальные.


Да, проверил, точно реальные

ПК>В случае наличия виртуального наследования в общем случае смещение получить невозможно, т.к. оно зависит от динамического типа объекта.


Да, несоменно ты прав. Но моя задача стояла "на статике" — то есть для конкретного типа смещение конкретного члена. В случае динамики (то есть когда мне бы потребовалось взять смещение члена относительно начала имеющегося объекта) вполне подошел обычный указатель на переменную-член.

ПК>Лучше рассказать, в чем заключается решаемая проблема, и, может быть, кто-нибудь сможет подсказать другое решение начальной задачи.


Не скажу. Как я уже признавался, это скорее академический вопрос
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.