Давайте постулировать ваш заголовок начинается что-то вроде этого:
class X
{
public:
...la de dah...
private:
struct Impl;
Impl* p_impl_;
};
Тогда при добавлении функции у вас есть выбор, чтобы сделать:
у вас есть определение функции X
элемент реализации логики , ссылаясь на p_impl_->
вещи повсюду, или
return p_impl->same_fn(all_the_args);
и kee p логика внутри класса Impl
?
Если вы выберете 1., вы получите объявление функции в заголовке и (чуть более грязное, чем обычно) определение в соответствующем файле реализации.
Если вы выберете 2. то вы получите объявление функции в файле заголовка, определение обертывания/пересылки в соответствующем файле реализации и, как минимум, определение в структуре Impl
(я, как правило, не определяю функции вне определения класса Impl
- это деталь реализации, и интерфейс все равно не является общедоступным).
В этой ситуации вообще нет желательного способа улучшить ситуацию (например, макро-хакерство и дополнительные сценарии генерации кода в процессе сборки могут быть оправданными, но очень редко).
Это не имеет значения, целую кучу, хотя это может быть интересно, что вариация второго подхода заключается в первом реализовать класс, который не использовать Pimpl идиомы (в комплекте с правильной головой и необязательно встроенные функции), вы можете затем обернуть с помощью объекта управления pimpl и переслать ему функции, и таким образом вы сохраняете свободу иметь какой-то код где-нибудь, когда-нибудь решите, что он хочет использовать функциональность, не используя оболочку pimpl , возможно, для повышения производительности/сокращения использования памяти за счет зависимости от перекомпиляции. Вы также можете сделать это, чтобы использовать конкретное создание шаблона без раскрытия кода шаблона.
Чтобы проиллюстрировать этот вариант (в соответствии с просьбой в комментарии), давайте начнем с глупым не-Pimpl class X
в своих собственных файлах, а затем создать Pimpl::X
оболочки (использование пространства имен и то же имя класса совершенно не обязательно, но облегчает листать код клиента использовать либо, и напоминание - это не значит быть кратким, дело здесь, чтобы версия, не Pimpl быть полезной тоже):
// x.h
class X
{
public:
int get() const { return n_; } // inline
void operator=(int); // out-of-line definition
private:
int n_;
};
// x.c++
#include <x.h>
void X::operator=(int n) { n_ = n * 2; }
// x_pimpl.h
namespace Pimpl
{
class X
{
public:
X();
X(const X&);
~X();
X& operator=(const X&);
int get() const;
void operator=(int);
private:
struct Impl;
Impl* p_impl_;
};
}
x_pimpl.c++
#include <x.h>
namespace Pimpl
{
struct X::Impl
{
::X x_;
};
// the usual handling...
X() : p_impl_(new Impl) { }
X(const X& rhs) : p_impl(new Impl) { p_impl_->x_ = rhs.p_impl_->x_; }
~X() { delete p_impl_; }
X& operator=(const X& rhs) { p_impl_->x_ = rhs.p_impl_->x_; return *this; }
// the wrapping...
int X::get() const { return p_impl_->x_.get(); }
void X::operator=(int n) { p_impl_->x_ = n; }
}
Если вы выберете для выше изменения на 2, что делает «реализацию» пригодной для использования сущностью в ее собственном праве, тогда да - вы можете получить 2 объявления и 2 определения, относящиеся к одной функции, но тогда одно из определений будет простая функция обертки/пересылки, которая является только значительно повторяющейся и утомительной, если функции очень короткие и многочисленные, но имеют множество параметров.
Это может быть очень ясно для вас, но я боюсь, что мне не ясна , У вас есть примеры кода, чтобы показать неприятности, с которыми вы сталкиваетесь? –
Почему вы вообще определяете эти функции в Impl? Объявите функцию в заголовке, а затем определите ее в «нижнем конце .cpp». –
@WojtekSurowka _'Declare функция в заголовке, '_ Это было бы не очень полезно с помощью идиомы [Pimpl] (http://en.wikipedia.org/wiki/Opaque_pointer), все дело в том, что реализация не является общедоступной в заголовке. –