Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 26.08.13 12:26
Оценка:
Что-то не могу решить красиво, на первый взгляд, простую задачку:
class A
{
public:

A(...); // Какие-то параметры

protected:

class Private;
typedef std::shared_ptr<Private> PrivatePtr;

A(PrivatePtr that);

PrivatePtr m_private; // Реализация
};

class B : public A
{
public:

B(...); // Какие-то параметры

protected:

class Private;
typedef std::shared_ptr<Private> PrivatePtr;

PrivatePtr m_private; // Реализация
};

class A::Private
{
public:

Private(...); // Какие-то параметры
};

class B::Private : public A::Private
{
public:

Private(...); // Какие-то параметры
};

Структура классов как у паттерна Bridge, только у меня не интерфейсы и реализация, а открытая и закрытая реализация. Поэтому чем-то смахивает на Pimpl еще, но иерархии классов две.
Не могу придумать как в конструкторе производного класса B проинициализировать сразу и родителя (класс A) и переменную член. Может кто-нибудь подскажет идеи???
Re: Pimpl, Brigde, наследование
От: Кодт Россия  
Дата: 26.08.13 12:57
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

<>

Если конструктор A прозрачный, т.е. вызывает конструктор A::Private с теми же аргументами, что переданы в A, то всё достаточно просто.

A::Private(aaa) {...aaa...}
A::A(aaa) : m_private(new A::Private(aaa)) {}

B::Private(aaabbb) : A::Private(aaa) {...bbb...} // как инициализировать реализацию предка - знает реализация потомка
B::B(aaabbb) : A(new B::Private(aaabbb)) {}


Если конструктор непрозрачный, то придётся повыкручиваться с инверсией.
Например, пусть A имеет статическую функцию, отображающую аргументы своего конструктора на кортеж аргументов конструктора реализации.
A::Private(AConfig) {...} // здесь - только логика создания реализации
A::A(aaa) : m_private(new A::Private(aconfig(aaa))) {} // а здесь - логика трансляции аргументов

B::Private(AConfig,BConfig) : A::Private(AConfig) {...} // здесь - только логика создания реализации, той и другой

B::B(aaabbb) : A(new B::Private(aconfig(aaa),bconfig(bbb))) {} // а здесь - и трансляция своих аргументов в аргументы предка, и своих в аргументы своей реализации
Перекуём баги на фичи!
Re[2]: Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 26.08.13 13:15
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Если конструктор A прозрачный, т.е. вызывает конструктор A::Private с теми же аргументами, что переданы в A, то всё достаточно просто.

В вашей терминологии он прозрачный, да

К>
К>A::Private(aaa) {...aaa...}
К>A::A(aaa) : m_private(new A::Private(aaa)) {}

К>B::Private(aaabbb) : A::Private(aaa) {...bbb...} // как инициализировать реализацию предка - знает реализация потомка
К>B::B(aaabbb) : A(new B::Private(aaabbb)) {}
К>

Вот тут и проблема, у меня, по задумке, указатели в B и A должны указывать на один и тотже объект (поэтому и shared_ptr), но на разные уровни в иерархии Private. А... даже если пока упростить и рассмотреть ваш вариант: я не понимаю как у вас теперь достучаться в B::Private из B класса? Или я туплю?
Re[3]: Pimpl, Brigde, наследование
От: Кодт Россия  
Дата: 26.08.13 14:44
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Вот тут и проблема, у меня, по задумке, указатели в B и A должны указывать на один и тотже объект (поэтому и shared_ptr), но на разные уровни в иерархии Private. А... даже если пока упростить и рассмотреть ваш вариант: я не понимаю как у вас теперь достучаться в B::Private из B класса? Или я туплю?


Во-первых, если нет желания делиться объектом-реализацией между несколькими разными экземплярами A или B, то shared_ptr оказывается избыточен.
Разве что спрятать деструктор реализации (shared_ptr запоминает его в рантайме).
Но это же можно сделать и с unique_ptr, у него есть параметр Deleter, реализация которого не обязана быть инлайном.

Во-вторых, это вопрос приведения типов, ну так и голые указатели/ссылки, и shared_ptr, и unique_ptr прекрасно приводятся и вверх, и вниз.

В сумме, получается такое
class A
{
  class PrivateA;
  struct PrivateDeleter
  {
    void operator()(PrivateA* p)const; // не инлайновый, определён после определения PrivateA, делает delete p;
  };
  typedef std::unique_ptr<PrivateA,PrivateDeleter> PrivatePtr;

public:
  A(aaaaa); // не инлайновый, определён после определения Private, делает m_private(new PrivateA(aaaaa))

protected:
  A(PrivatePtr&& p) : m_private(p) {}

  PrivateA& privateA() const { return *m_private; }
};

class B : public A
{
  class PrivateB; // : public A::PrivateA

public:
  B(bbbbb); // не инлайновый, определён после определения Private, делает : A(PrivatePtr(new PrivateB(bbbbb))) {}

protected:
  PrivateB& privateB() const { return static_cast<PrivateB&>(privateA()); }
};
Перекуём баги на фичи!
Re[4]: Pimpl, Brigde, наследование
От: Кодт Россия  
Дата: 26.08.13 14:59
Оценка:
К>В сумме, получается такое
К>class A
К>{
К>  class PrivateA;
К>  struct PrivateDeleter
К>  {
К>    void operator()(PrivateA* p)const; // не инлайновый, определён после определения PrivateA, делает delete p;
К>  };
К>  typedef std::unique_ptr<PrivateA,PrivateDeleter> PrivatePtr;

Здесь обязательно, чтобы у PrivateA был виртуальный деструктор.
Или же можно эту виртуальность перетащить из класса в экземпляр:
typedef void (*TotalDeleter)(void*); // по мотивам boost::checked_delete
typedef std::unique_ptr<PrivateA, TotalDeleter> PrivatePtr;

// в .cpp

template<class T> void total_deleter(void* p) { delete (T*)p; } // в 11 стандарте не нашёл ничего похожего, может, плохо искал.

A::A(aaaaa) : m_private(new A(aaaaa), total_deleter<A>) {}

B::B(bbbbb) : A(PrivatePtr(new B(bbbbb), total_deleter<B>)) {}
Перекуём баги на фичи!
Re[3]: Pimpl, Brigde, наследование
От: _smit Россия  
Дата: 26.08.13 15:02
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Здравствуйте, Кодт, Вы писали:


К>>Если конструктор A прозрачный, т.е. вызывает конструктор A::Private с теми же аргументами, что переданы в A, то всё достаточно просто.

ATP>В вашей терминологии он прозрачный, да

К>>
К>>A::Private(aaa) {...aaa...}
К>>A::A(aaa) : m_private(new A::Private(aaa)) {}

К>>B::Private(aaabbb) : A::Private(aaa) {...bbb...} // как инициализировать реализацию предка - знает реализация потомка
К>>B::B(aaabbb) : A(new B::Private(aaabbb)) {}
К>>

ATP>Вот тут и проблема, у меня, по задумке, указатели в B и A должны указывать на один и тотже объект (поэтому и shared_ptr), но на разные уровни в иерархии Private. А... даже если пока упростить и рассмотреть ваш вариант: я не понимаю как у вас теперь достучаться в B::Private из B класса? Или я туплю?

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

Короткое отступление, лучше называть B -- base class and D -- derived class.

Если ориентироваться на GoF, то в брижде будут взаимодействовать абстрактные классы. Соответственно, бридж настраивается просто через указатель на заранее инстанцированный класс реализации. Можно и динамически в процессе работы проинициализировать указатель на реализацию.

Хотелось бы предостеречь тебя от вычурности с таким наследованием и вложенностью классов. То, что неудобно проинициализировать -- это первый звоночек. Может есть более простое и элегантное решение получить то, что ты задумал? Извини, что только предостерёг, но на вопрос прямо не ответил.
Re[5]: Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 26.08.13 15:28
Оценка:
Здравствуйте, Кодт, Вы писали:

К>> skipped...


Да у меня примерно такая реализация как у вас и получается. shared_ptr тут, чисто, для иллюстрации что Private расщаривается между A и B, я за него не держусь...
Я понимаю что можно привести вверх типы, но это именно то, чего я пытался избежать. Что я называю некрасивым:
В конструкторе B появляется тип B::Private и вот, он — есть, бери и присваивай. Но он "спускается" полиморфно в класс A, а затем его нужно доставать от туда, используя dynamic_cast. А как же статическая проверка типов?
А потом а если я не хочу в реализации использовать virtual методы....? В общем надеялся что такую простую задачу можно решить не теряя информацию о типах.
Re[4]: Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 26.08.13 15:35
Оценка:
Здравствуйте, _smit, Вы писали:

_>Skipped...


Спасибо за предостережение. Я понимаю что есть абстрактные паттерны, но на практике бывают случаи где паттерны не всегда используются в чистом виде. Чаше как база, от которой можно отталкиваться и строить что-то более сложное. Я понимаю что данные сложности говорят о том что я что-то делаю неправильно. Если бы не понимал, я бы не задавал вопрос в форуме. Но все равно спасибо за ответы.
Re[5]: Pimpl, Brigde, наследование
От: _smit Россия  
Дата: 26.08.13 18:32
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:
ATP>Здравствуйте, _smit, Вы писали:
_>>Skipped...
ATP>Спасибо за предостережение. Я понимаю что есть абстрактные паттерны, но на практике бывают случаи где паттерны не всегда используются в чистом виде. Чаше как база, от которой можно отталкиваться и строить что-то более сложное. Я понимаю что данные сложности говорят о том что я что-то делаю неправильно. Если бы не понимал, я бы не задавал вопрос в форуме. Но все равно спасибо за ответы.

Согласен, правильно делаешь, что спрашиваешь. Просто, глядя на код, возникает ощущение, что "истина где-то рядом". Хорошее решение часто выкристаллизовывается в процессе кодирования и последующего рефакторинга (примеры из Роберт К. Мартин "Быстрая разработка программ"). Многие даже предостерегают от преждевременного утверждения архитектуры, например, нравится шутка про специалиста из: http://www.insidecpp.ru/art/38/.

Есть ещё один способ, двигаться не от реализации к использованию, а попробовать наоборот, от использования к реализации -- аналог TDD. То есть, как ты (или коллеги) будут использовать твое решение. А то убьёш кучу времени, сделаешь реализацию, а пользоваться неудобно. Это как раз причина, по которой я не смог подсказать, как инициализировать конструкторы, т.к. я не понимаюпредставляю, как и для чего будут использоваться твои классы. Посмотри на правило 32 http://www.rsdn.ru/res/book/cpp/cppstandards.xml
Автор(ы): Герб Саттер, Андрей Александреску

Эта книга поможет новичку стать профессионалом, так как в ней
представлен сконцентрированный лучший опыт программистов на C++,
обобщенный двумя экспертами мирового класса. Начинающий программист
найдет в ней простые и понятные рекомендации для ежедневного
использования, подкрепленные примерами их конкретного применения
на практике.
(здесь можно посмотреть полный текст). Это конечно не аксиома, а лишь правило, но прислушаться стоит, т.к. у тебя конкретные классы используются в качестве базовых, конфликт.

Можно описать исходные условия и как ты видишь реализацию, если это не коммерческая тайна конечно, а мы попробуем совместно что-то от себя посоветовать. Бывает, когда сформулируешь, задачу, то и ответ сам приходит
Re[6]: Pimpl, Brigde, наследование
От: Кодт Россия  
Дата: 26.08.13 19:22
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Да у меня примерно такая реализация как у вас и получается. shared_ptr тут, чисто, для иллюстрации что Private расщаривается между A и B, я за него не держусь...

ATP>Я понимаю что можно привести вверх типы, но это именно то, чего я пытался избежать. Что я называю некрасивым:
ATP>В конструкторе B появляется тип B::Private и вот, он — есть, бери и присваивай. Но он "спускается" полиморфно в класс A, а затем его нужно доставать от туда, используя dynamic_cast. А как же статическая проверка типов?

Зачем dynamic_cast, если static_cast?
Или там виртуальное наследование и всякие страсти заранее предполагаются?

ATP>А потом а если я не хочу в реализации использовать virtual методы....? В общем надеялся что такую простую задачу можно решить не теряя информацию о типах.


И не нужны тут виртуальные функции. Почти не нужны, потому что удалять реализацию придётся полиморфно. А этот полиморфизм придётся или в реализацию засовывать, в виде виртуального деструктора, или в указатель, в виде checked_delete, или в класс-фасад A и B, в виде, опять же, виртуального деструктора.
Перекуём баги на фичи!
Re[7]: Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 27.08.13 07:59
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Зачем dynamic_cast, если static_cast?

К>Или там виртуальное наследование и всякие страсти заранее предполагаются?

A<---B (B наследует реализацию A и добавляет что-то своё). A::Private<---B::Private (Private от B наследует реализацию Private от A и добавляет что-то своё). Теперь я к конструкторе класса B создаю B::Private и передаю конструктору класс A. Но в B мне также нужна "ссылка" на этот же B::Private класс. Как её получить без dynamic_cast из указателя A::Private? Или у меня ошибка здесь и вы предлагаете другое?
Re[5]: Pimpl, Brigde, наследование
От: Кодт Россия  
Дата: 27.08.13 08:11
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Спасибо за предостережение. Я понимаю что есть абстрактные паттерны, но на практике бывают случаи где паттерны не всегда используются в чистом виде. Чаше как база, от которой можно отталкиваться и строить что-то более сложное. Я понимаю что данные сложности говорят о том что я что-то делаю неправильно. Если бы не понимал, я бы не задавал вопрос в форуме. Но все равно спасибо за ответы.


Да тут не какой-то абстрактный ооп-паттерн, а скорее идиома конкретного языка, а именно сиплюсплюсный пимпл.
Почему пимпл актуален именно для С++?
Потому что в других языках модульная система и организация памяти даёт достаточные механизмы для абстрагирования, а в плюсах с их огромным количеством инлайнов (включая встраивание тела объекта в память на стеке и в тело объекта-владельца — это ведь тоже инлайн-информация, по сути) приходится выкручиваться, достраивая необходимое на лету.

Итак, пимпл решает 5 основных задач:
— сделать объект-фасад фиксированного типа (так же, как эту задачу решают и фиксированные указатели на полиморфные типы)
— сделать объект-фасад фиксированного и небольшого размера (опять же, указатели делают то же самое)
— сделать простую для пользователя фабрику реализации (указатель, будучи примитивным типом, инициализируется как Ptr p(new Obj(blablablablabla)), тогда как Pimpl p(blabla))
— скрыть ненужные зависимости, разорвать кольцевые зависимости (класс реализации можно определить позже декоратора, вплоть до другой единицы трансляции)
— скрыть ненужные детали реализации

Вопрос: а что из этого тебе реально потребовалось?

Вполне возможно, что можно обойтись пимплом для бедных: shared_ptr<InterfaceOfA> и двумя функциями-фабриками makeA(aaa), makeB(bbb).
Это я так, для примера. Возможно, что и невозможно в конкретном случае :):
Перекуём баги на фичи!
Re[8]: Pimpl, Brigde, наследование
От: Кодт Россия  
Дата: 27.08.13 11:18
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:


ATP>A<---B (B наследует реализацию A и добавляет что-то своё). A::Private<---B::Private (Private от B наследует реализацию Private от A и добавляет что-то своё). Теперь я к конструкторе класса B создаю B::Private и передаю конструктору класс A. Но в B мне также нужна "ссылка" на этот же B::Private класс. Как её получить без dynamic_cast из указателя A::Private? Или у меня ошибка здесь и вы предлагаете другое?


Внимание, фокус
// накидай в тела классов всякую дребедень по вкусу
class Foo { ..... };
class Bar : public Foo { ..... };

int main()
{
  Bar* b = new Bar;
  Foo* f = b;
  assert( static_cast<Bar*>(f) == b ); // только если нет виртуального наследования
  assert( dynamic_cast<Bar*>(f) == b ); // только при наличии в Foo виртуальных методов
  assert( reinterpret_cast<Bar*>(f) == b ); // самое стрёмное место: компилятор может сделать сдвиг базы, static_cast его учитывает, reinterpret - нет
}
Перекуём баги на фичи!
Re[9]: Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 27.08.13 12:01
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Внимание, фокус

К>
К>// накидай в тела классов всякую дребедень по вкусу
К>class Foo { ..... };
К>class Bar : public Foo { ..... };

К>int main()
К>{
К>  Bar* b = new Bar;
К>  Foo* f = b;
К>  assert( static_cast<Bar*>(f) == b ); // только если нет виртуального наследования
К>  assert( dynamic_cast<Bar*>(f) == b ); // только при наличии в Foo виртуальных методов
К>  assert( reinterpret_cast<Bar*>(f) == b ); // самое стрёмное место: компилятор может сделать сдвиг базы, static_cast его учитывает, reinterpret - нет
К>}
К>


— я так понимаю, все проходит корректно так как первые две строчки main — рядом. А если:

B::B(new A) 
{
m_private = static_cast<B::Private*>(A::GetPrivate()); // Возвращаем m_private из A
}

Такое разве прокатит?
Re[10]: Pimpl, Brigde, наследование
От: Кодт Россия  
Дата: 27.08.13 12:45
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP> — я так понимаю, все проходит корректно так как первые две строчки main — рядом. А если:

ATP>B::B(new A)
ATP>Такое разве прокатит?

А вот нечего копировать A в B.
Копировать можно базу в базу, наследника в наследника, и с рядом оговорок — наследника в базу (при этом возникает срезка, иногда — с катастрофическими последствиями, иногда — полностью безопасно).

Ну а так, если ты знаешь тип источника (>B и >B::Private, пусть для определённости это будут C и C::Private), тип приёмника (B и B::Private),
то статическое приведение C::Private* к A::Private* (в момент создания источника) и обратно к B::Private* (при копировании) эквивалентно приведению C::Private* к B::Private*.
А уж если тип источника и приёмника совпадает, то сам бог велел!
Перекуём баги на фичи!
Re[10]: Pimpl, Brigde, наследование
От: saf_e  
Дата: 28.08.13 08:04
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Здравствуйте, Кодт, Вы писали:


К>>Внимание, фокус

К>>
К>>// накидай в тела классов всякую дребедень по вкусу
К>>class Foo { ..... };
К>>class Bar : public Foo { ..... };

К>>int main()
К>>{
К>>  Bar* b = new Bar;
К>>  Foo* f = b;
К>>  assert( static_cast<Bar*>(f) == b ); // только если нет виртуального наследования
К>>  assert( dynamic_cast<Bar*>(f) == b ); // только при наличии в Foo виртуальных методов
К>>  assert( reinterpret_cast<Bar*>(f) == b ); // самое стрёмное место: компилятор может сделать сдвиг базы, static_cast его учитывает, reinterpret - нет
К>>}
К>>


ATP> — я так понимаю, все проходит корректно так как первые две строчки main — рядом. А если:


ATP>
ATP>B::B(new A) 
ATP>{
ATP>m_private = static_cast<B::Private*>(A::GetPrivate()); // Возвращаем m_private из A
ATP>}
ATP>

ATP>Такое разве прокатит?

Я в подобной ситуации делал так: существовало две параллельные иерархии классов, имплементационная со своими .h, .cpp "для своих" т.е. эти хедера наружу не светились, и интерфейсная в общем случае тоже с .h и .cpp.

Выглядело примерно так:

public.h

class A
{
public:
  class impl; // поскольку impl не виден наружу можем смело делать его public

  A(impl *ptr = nullptr); // если impl != nullptr запоминаем, иначе создаем

// методы, методы, методы...
};

class B : public A
{
public:
  class impl;

  B(impl *ptr = nullptr); // если impl != nullptr запоминаем, иначе создаем

// методы, методы, методы...
};


private.h

class impl::A
{
};

class impl::B : public impl::A
{
};


Но прежде чем такое делать, надо серьезно подумать о целесообразности. Кол-во файлов и геморроя умножается на 2
Re[11]: Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 28.08.13 09:12
Оценка:
Здравствуйте, saf_e, Вы писали:

_>Но прежде чем такое делать, надо серьезно подумать о целесообразности. Кол-во файлов и геморроя умножается на 2


Убедили, убедили, я полностью изменил реализацию, спрямив кое-где углы используя частные особенности данных. Теперь у меня остался чисто программерский интерес, как токе, всё таки, можно сделать.

_>Я в подобной ситуации делал так: существовало две параллельные иерархии классов, имплементационная со своими .h, .cpp "для своих" т.е. эти хедера наружу не светились, и интерфейсная в общем случае тоже с .h и .cpp.


_>Выглядело примерно так:


_>
_>public.h

_>class A
_>{
_>public:
_>  class impl; // поскольку impl не виден наружу можем смело делать его public

_>  A(impl *ptr = nullptr); // если impl != nullptr запоминаем, иначе создаем

_>// методы, методы, методы...
_>};

_>class B : public A
_>{
_>public:
_>  class impl;

_>  B(impl *ptr = nullptr); // если impl != nullptr запоминаем, иначе создаем

_>// методы, методы, методы...
_>};


_>private.h

_>class impl::A
_>{
_>};

_>class impl::B : public impl::A
_>{
_>};
_>


Ну так это в точности тоже самое что и у меня . Это мне и нужно... А расскажите про самое интересное: если B::impl создавать снаружи B то, да проблем нет. Но я то, пытаюсь сделать чтобы B создавал impl в конструкторе. Тогда имеем:
B::B(...) 
: A(new B::impl(...))
, m_imple(????) // Как сюда получить копию указателя ????
{
...
}

указатель может получить либо A, либо B. Этот вопрос можно как-то красиво решить?
Re[12]: Pimpl, Brigde, наследование
От: saf_e  
Дата: 28.08.13 09:20
Оценка: 6 (1)
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Здравствуйте, saf_e, Вы писали:


ATP>Ну так это в точности тоже самое что и у меня . Это мне и нужно... А расскажите про самое интересное: если B::impl создавать снаружи B то, да проблем нет. Но я то, пытаюсь сделать чтобы B создавал impl в конструкторе. Тогда имеем:

ATP>
ATP>B::B(...) 
ATP>: A(new B::impl(...))
ATP>, m_imple(????) // Как сюда получить копию указателя ????
ATP>{
ATP>...
ATP>}
ATP>

ATP>указатель может получить либо A, либо B. Этот вопрос можно как-то красиво решить?

Вот так можно (не скажу что красиво)

B::B(impl *p_impl = nullptr) : A(!p_impl ? p_impl = new impl() : p_impl), m_impl(p_impl) {}


Если класс B не имеет p_impl в конструкторе, то делайте static_cast от A::mp_impl и не парьтесь. У вас наверняка известно что это производные классы.
Re[13]: Pimpl, Brigde, наследование
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 28.08.13 11:44
Оценка:
Здравствуйте, saf_e, Вы писали:

_>Вот так можно (не скажу что красиво)


_>
_>B::B(impl *p_impl = nullptr) : A(!p_impl ? p_impl = new impl() : p_impl), m_impl(p_impl) {}
_>


Странно, у меня на такое компилятор выдавал предупреждение, что я использую не инициализированную переменную . Я понимаю что ничего страшного, но предупреждения я давно перестал терпеть...
Re[14]: Pimpl, Brigde, наследование
От: saf_e  
Дата: 28.08.13 11:48
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Здравствуйте, saf_e, Вы писали:


_>>Вот так можно (не скажу что красиво)


_>>
_>>B::B(impl *p_impl = nullptr) : A(!p_impl ? p_impl = new impl() : p_impl), m_impl(p_impl) {}
_>>


ATP>Странно, у меня на такое компилятор выдавал предупреждение, что я использую не инициализированную переменную . Я понимаю что ничего страшного, но предупреждения я давно перестал терпеть...


И мне странно, она со всех сторон инициализирована возможно у вас там что-то еще...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.