C ++, статически определять базовые классы с разными адресами? - PullRequest
2 голосов
/ 15 июля 2009

Если у меня есть производный класс с несколькими базами, каждый указатель this для каждой базы будет отличаться от указателя this этого производного объекта, за исключением одного. Учитывая два типа в иерархии наследования, я хотел бы определить во время компиляции, имеют ли они один и тот же указатель this. Нечто подобное должно работать, но не работает:

BOOST_STATIC_ASSERT(static_cast<Base1*>((Derived *)0xDEADBEEF) == (Derived*)0xDEADBEEF);

Потому что это должно быть «целочисленное константное выражение», и в соответствии со стандартом допускается только целочисленное приведение (что глупо, потому что им нужна только информация времени компиляции, если не используется виртуальное наследование). Та же проблема возникает при попытке передать результаты в виде целочисленных параметров шаблона.

Лучшее, что я смог сделать, - это проверить при запуске, но мне нужна информация во время компиляции (чтобы заставить работать несколько глубоких шаблонов).

Ответы [ 6 ]

2 голосов
/ 02 сентября 2010

Я пытаюсь решить эту же проблему. У меня есть реализация, которая работает, если вы знаете, какая переменная-член находится в начале макета базового класса. Например. если переменная-член "x" существует в начале каждого класса, то следующий код будет работать для получения смещения байтов конкретной компоновки базового класса из компоновки производного класса: offsetof (производный, base2 :: x).

В случае:
struct base1 { char x[16]; };<br> struct base2 { int x; };<br> struct derived : public base1, public base2 { int x; };<br> static const int my_constant = offsetof(derived, base2::x);

Компилятор правильно назначит "16" для my_constant в моей архитектуре (x86_64).

Сложность состоит в том, чтобы получить "16", когда вы не знаете, какая переменная-член находится в начале макета базового класса.

2 голосов
/ 15 июля 2009

Я не знаю, как проверить, что вы хотите, но обратите внимание, что ваше предположение неверно при наличии пустых базовых классов. Любое число из них может иметь одинаковое смещение от начала объекта, если они имеют другой тип.

1 голос
/ 15 июля 2009

Как насчет использования

BOOST_STATIC_ASSERT(boost::is_convertible<Derived*,Base*>::value)

как указано в следующих местах ...

http://www.boost.org/doc/libs/1_39_0/doc/html/boost_staticassert.html

http://www.boost.org/doc/libs/1_38_0/libs/type_traits/doc/html/boost_typetraits/reference/is_convertible.html

1 голос
/ 15 июля 2009

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

1 голос
/ 15 июля 2009

Я даже не уверен, что это смещение является константой в первую очередь. У вас есть нормативная формулировка, предлагающая иное?

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

0 голосов
/ 15 июля 2009

Я не осознавал, что компилятор вставит эту проверку во время выполнения, но ваши основные предположения не совсем верны. Вероятно, не так, как вас волнует: компилятор может использовать Оптимизацию Пустого Базового Класса, если вам случается наследовать от более чем одного базового класса с sizeof(base class)==0. Это приведет к (base class *)(derived *)1==at least one other base class.

Как я уже сказал, это, вероятно, не то, о чем вам действительно нужно заботиться.

...