Стандарты программирования на С++. 101 правило и рекомендация | страница 77
Примечание: объявляйте указатель на закрытую реализацию, как показано — с использованием двух объявлений. Если вы скомбинируете две строки с предварительным объявлением типа и указателя на него в одну инструкцию >struct Impl *pimpl;
это будет вполне законно, но изменит смысл объявления: в этом случае >Impl
находится в охватывающем пространстве имен и не является вложенным типом вашего класса.
Имеется как минимум три причины для использования Pimpl, и все они вытекают из различия между доступностью (в состоянии ли вы вызвать или использовать некоторый объект) и видимостью (видим ли этот объект для вас и, таким образом, зависите ли вы от его определения) в С++. В частности, все закрытые члены класса недоступны никому, кроме функций- членов и друзей, но зато видимы всем — любому коду, которому видимо определение класса.
Первое следствие этого — потенциально большее время сборки приложения из-за обработки излишних определений типов. Для закрытых данных-членов, хранящихся по значению, и параметров закрытых функций-членов, передаваемых по значению или используемых в видимой реализации функций, типы должны быть определены, даже если они никогда не потребуются в данной единице компиляции. Это может привести к увеличению времени сборки, например:
>class C {
> // ...
>private:
> AComplicatedType act_;
>}
Заголовочный файл, содержащий определение класса С, должен также включать заголовочный файл, содержащий определение >AComplicatedType
, который в свою очередь транзитивно включает все заголовочные файлы, которые могут потребоваться для определения >AComplicatedType
, и т.д. Если заголовочные файлы имеют большие размеры, время компиляции может существенно увеличиться.
Второе следствие — создание неоднозначностей и сокрытие имен для кода, который пытается вызвать функцию. Несмотря на то, что закрытая функция-член не может быть вызвана кодом вне ее класса и его друзей, она тем не менее участвует в поиске имен и разрешении перегрузки и тем самым может сделать вызов неоднозначным или некорректным. Перед выполнением проверки доступности С++ выполняет поиск имен и разрешение перегрузки. Из-за этого видимость имеет более высокий приоритет:
>int Twice(int); // 1
>class Calc {
>public:
> string Twice(string); // 2
>private:
> char* Twice(char*); // 3
> int Test() {
> return Twice(21); // A: ошибка, функции 2 и 3 не
> // подходят (могла бы подойти функция 1, но
> // ее нельзя рассматривать, так она скрыта от