Преобразовать указатель на член в указатель на класс
От: Аноним  
Дата: 08.11.10 21:06
Оценка:
Есть объект класса С++, и я знаю указатель на один из его членов.
Как получить указатель на сам объект? Можно ли это сделать без грязных хаков, offsetof-ов, reinterpret_cast-ов и пр. ?

class Foo {
 public:
  Foo(): m_n(0) {}

 public:
  int m_n;
};

Foo* foo_member_cast(int* pi);

void main()
{
  Foo foo;
  int *pi=&foo.m_n;

  Foo *pfoo=foo_member_cast(pi);

  assert(pfoo==&foo);
}

Foo* foo_member_cast(int* pi)
{
// How to realize it?
}
Re: AFAIK, никак.
От: Erop Россия  
Дата: 08.11.10 21:08
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Есть объект класса С++, и я знаю указатель на один из его членов.

А>Как получить указатель на сам объект? Можно ли это сделать без грязных хаков, offsetof-ов, reinterpret_cast-ов и пр. ?

AFAIK, никак.
А в общем случае и с хаками не решается...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Преобразовать указатель на член в указатель на класс
От: jazzer Россия Skype: enerjazzer
Дата: 09.11.10 02:22
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Есть объект класса С++, и я знаю указатель на один из его членов.

А>Как получить указатель на сам объект? Можно ли это сделать без грязных хаков, offsetof-ов, reinterpret_cast-ов и пр. ?

Без хаков — нельзя, int* не содержит никакой информации о классе. Так что только через offsetof+reinterpret_cast, но это ,сам понимаешь, хождение по граблям, потому что ты никак не сможешь проконтролировать в коде, что указатель, который к тебе пришел, указывает именно на нужный член нужного класса.
А что за задача возникла, что такое понадобилось?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Преобразовать указатель на член в указатель на класс
От: night beast СССР  
Дата: 09.11.10 04:58
Оценка:
Здравствуйте, jazzer, Вы писали:

А>>Есть объект класса С++, и я знаю указатель на один из его членов.

А>>Как получить указатель на сам объект? Можно ли это сделать без грязных хаков, offsetof-ов, reinterpret_cast-ов и пр. ?

J>Без хаков — нельзя, int* не содержит никакой информации о классе. Так что только через offsetof+reinterpret_cast, но это ,сам понимаешь, хождение по граблям, потому что ты никак не сможешь проконтролировать в коде, что указатель, который к тебе пришел, указывает именно на нужный член нужного класса.

J>А что за задача возникла, что такое понадобилось?

иногда это бывает оправданно.
здесь
Автор: night beast
Дата: 01.11.10
Re[2]: Преобразовать указатель на член в указатель на класс
От: Tscheineg  
Дата: 09.11.10 15:31
Оценка:
J>А что за задача возникла, что такое понадобилось?

Для чего это может быть нужно?

Пусть есть классы Фу и Бар, причем классу Бар для работы нужно обращаться к объекту класса Фу. Естественное решение — иметь внутри класса Бар ссылку на объект Фу:
class Foo {
 public:
  void Do() {}
};

class Bar1 {
 public:
  Bar1(Foo &foo)
   : m_foo(foo) {}
  
 public:
  void Do() { m_foo.Do(); }
  
 private:
  Foo &m_foo;
};


Поскольку Бар должен работать в содружестве с Фу, то естественно сделать класс-оболочку Фубар, который будет содержать в себе и Фу, и Бар:
class Foobar1 {
 public:
  Foobar1()
   : m_bar(m_foo) {}
   
 public:
  void Do() { m_bar.Do(); }

 private:
  Foo m_foo;
  Bar1 m_bar;
};


А теперь подумаем. Зачем m_bar содержит в себе ссылку на лежащий рядом с ним m_foo?
Ведь m_bar знает указатель на себя (свой this), а компилятор знает смещение между m_foo и m_bar. То есть, m_bar может вычислить указатель на m_foo, и хранить его не нужно.

Так что, если предполагается, что Фу и Бар всегда будут использоваться в составе некой Фубар-оболочки, то, теоретически можно было бы выкинуть из Бара ссылку на Фу, заменить ее этакой compile-time ссылкой.

Что-то вроде того:

template <typename FOOBAR>
class Bar2 {
 public:
  void Do() { RetrieveFoo().Do(); }
  
 private:
  Foo& RetrieveFoo() { return member_cast<FOOBAR&>(*this).m_foo; }
};

class Foobar2 {
 public:
  void Do() { m_bar.Do(); }

 private:
  Foo m_foo;
  Bar2<Foobar2> m_bar;
};


Отмечу также еще пару достоинств такого подхода.
У Foobar1 есть явные проблемы с копируемостью. У Foobar2 их нет.
У Bar2 и Foobar2 нет дурацких конструкторов, которые были у Bar1 и Foobar1
Re[3]: Преобразовать указатель на член в указатель на класс
От: alpha80  
Дата: 10.11.10 17:32
Оценка:
Здравствуйте, Tscheineg, Вы писали:

T>Отмечу также еще пару достоинств такого подхода.

T>У Foobar1 есть явные проблемы с копируемостью. У Foobar2 их нет.

А какие у Foobar1 проблемы с копируемостью?
Re[3]: Преобразовать указатель на член в указатель на класс
От: A.Lokotkov Россия  
Дата: 10.11.10 17:48
Оценка: 1 (1) +1
Здравствуйте, Tscheineg, Вы писали:

T>Для чего это может быть нужно? [snip]


Я извиняюсь, это что-ли юмор такой? Или такой дизайн действительно случается в продакшн-коде?
bloß it hudla
Re[4]: Преобразовать указатель на член в указатель на класс
От: Tscheineg  
Дата: 13.11.10 12:03
Оценка:
Здравствуйте, alpha80, Вы писали:

A>А какие у Foobar1 проблемы с копируемостью?


Класс Foobar1 содержит два члена m_foo и m_bar, причем m_bar содержит ссылку на m_foo.
А также класс Foobar1 имеет автоматически сгенерированный копирующий конструктор.
Foobar1 fbA;      // fbA.m_bar содержит ссылку на fbA.m_foo
Foobar1 fbB(fbA); // fbB.m_bar содержит ссылку опять же на fbA.m_foo !!!


Хотя, логично было бы ожидать, чтобы fbB.m_bar ссылался бы на fbB.m_foo. Таким образом, автоматически сгенерированный копирующий конструктор Foobar1 нас не устраивает, значит, придется писать его вручную (или запрещать копирование)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.