Название: Pimpl inheritance через member shadowing Отправлено: kramer от Март 06, 2013, 18:14 Друзья! Я тут клепал PIMPL на макросах а-ля Qt, и мне подумалось, а что собственно плохого в member shadowing? Пожалуйста, скажите, будет ли это работать, и если нет, то почему? Компилятора под рукой нет, пишу с коробка спичек, а до завтра ждать не хочется:
Код
Т.е. мой ход мыслей таков: при создании класса-наследника через Derived() базовый класс получит срезку BaseImpl, и указатели Base::impl и Derived::impl будут одинаковыми, просто разных типов. Виртуальные функции, понятно, будут использовать соответствующий классу указатель, и наконец, во благовременье будет вызван виртуальный деструктор класса реализации, который и уничтожит созданное. А? Или я что-то недодумал? Название: Re: Pimpl inheritance через member shadowing Отправлено: Igors от Март 06, 2013, 18:59 Не компилил, полагаю что такая конструкция допустима, но выигрыша от нее никакого. Когда будете писать методы для Deived, он достанет "какoй impl - тот или этот". Придется писать Derived::impl - ну и за что боролись?
Название: Re: Pimpl inheritance через member shadowing Отправлено: Авварон от Март 06, 2013, 19:06 Работать будет, но немного не так. В классе Derived будет ДВА указателя (DerivedImpl *impl и BaseImpl *Base::impl). Работать будет как для двух отдельных указателей на отдельные объекты.
Такой подход применяется в KDE - они на каждом уровне иерархии открывают *d заново. Подход кутешников гораздо лучше. В вашем подходе (если кол-во классов в иерархии N) - N+1 выделений памяти (вместо 2), размер результирующего класса N*sizeof(void*) (вместо 1*sizeof(void*)), да и памяти больше за счет новых втейблов в Private классах. Всё мелочи, кроме большего количества вызовов malloc - это операция относительно дорогая и лучше ее не дергать лишний раз. Да, а еще d_func'и сохраняют константность d, в отличие от голого указателя в классе (то есть в конст ф-ии он просто так не даст поменять мембер) Igors Компилер возьмет верхний в иерархии impl (к-ый "ближе" по областям видимости) Название: Re: Pimpl inheritance через member shadowing Отправлено: kramer от Март 06, 2013, 19:22 В классе Derived будет ДВА указателя (DerivedImpl *impl и BaseImpl *Base::impl). Работать будет как для двух отдельных указателей на отдельные объекты. Т.е. таким образом, вы хотите сказать, что в коде Код указатели b и d будут иметь разные значения? UPD: Засада в том, что кутешный подход завязан на темплейтах, а у меня GCC 3.4 и шланг под маком. Я на GCC 3.4 с темплейтами один раз так обжегся, с тех пор на воду дую. :) Название: Re: Pimpl inheritance через member shadowing Отправлено: Авварон от Март 06, 2013, 19:36 Нет, с чего бы?
У вас случай Код: class Derived Название: Re: Pimpl inheritance через member shadowing Отправлено: kramer от Март 06, 2013, 19:46 Нет, с чего бы? Ну и господь с ним, лишних 8 байт на указатель не жалко, при моих-то 64Гб минимум. :) Просто из вашего ответа можно заключить, что для каждого члена иерархии создается отдельный класс реализации - однако в моем случае это не так, создается только класс реализации для вновь создаваемого класса, а всем предкам передается на него указатель, который благополучно срезается, и, кстати, вызов new тут получается только один. У вас случай Код: class Derived P.S. Я отредактировал предыдущий ответ, объяснив, почему мне не нравится d_func(). Название: Re: Pimpl inheritance через member shadowing Отправлено: Igors от Март 06, 2013, 19:55 вызов new тут получается только один. Согласен, 2 указателя равны. Все же как-то это "нездорово". Напр как будет выглядеть установка другого PIMPL? Название: Re: Pimpl inheritance через member shadowing Отправлено: kramer от Март 06, 2013, 20:08 Согласен, 2 указателя равны. Все же как-то это "нездорово". Напр как будет выглядеть установка другого PIMPL? Да я тоже думаю, что "нездорово", потому и спрашиваю. Мой PIMPL не подразумевает разных реализаций (если я правильно вас понял), он преследует только одну цель - спрятать реализацию от пользователя SDK, и заодно улучшить бинарную совместимость. А то там внутри такой бардак, стыдно глянуть. Если пользователю придет в голову использовать мой PIMPL - никто не мешает ему отнаследоваться от моих приватных классов, которые, пусть и нехотя, но все-таки поставляются с SDK. А если ему нужен свой собственный PIMPL - ну так пускай использует для него другое имя.Название: Re: Pimpl inheritance через member shadowing Отправлено: Авварон от Март 06, 2013, 20:45 А, я не заметил, что у вас передаётся impl потомка предку; каюсь. Да, так экземпляр приватного класса будет 1.
На самом деле не вижу, чем вам не нравится d_func() кутешный. Шаблоны там банальные, не могу представить где это не будет работать (ведь мембер-темплейты тут не нужны). Если боитесь шаблонов, напишите свой DECLARE_PRIVATE на макросах: Код: #define DECLARE_PRIVATE(Class) \ Название: Re: Pimpl inheritance через member shadowing Отправлено: kramer от Март 14, 2013, 14:44 Друзья! Я тут нашел любопытное решение для конст-корректности, которое плюс ко всему позволяет убрать в реализацию сам факт использования PIMPL, и теперь спешу поделиться. Нужно создать обертку для void* в виде
Код и в базовых классах интерфейса и реализации хранить ссылку на реализации и интерфейс в виде члена этого типа вместо BaseImpl* или void*. Инициализация проводится как и раньше, через защищенный конструктор, а для разыменования используются четыре макроса: Код Таким образом в заголовочном файле класса-потомка классе не будет вообще никаких упоминаний о PIMPL или классе реализации, и можно при необходимости его добавить, не внося никаких изменений в интерфейс. Вот мой код целиком: Код
Вот так вот. Буду благодарен за комментарии. |