Я вижу много исходного кода, который использует идиому PImpl в C ++. Я предполагаю, что его цель - скрыть личные данные / тип / реализацию, чтобы убрать зависимость, а затем уменьшить время компиляции и проблему включения заголовка.
Но интерфейсные / чисто абстрактные классы в C ++ также имеют эту возможность, их также можно использовать для сокрытия данных / типа / реализации. И чтобы позволить вызывающей стороне просто видеть интерфейс при создании объекта, мы можем объявить фабричный метод в заголовке интерфейса.
Сравнение:
Стоимость :
Стоимость пути интерфейса ниже, потому что вам даже не нужно повторять реализацию функции общедоступной оболочки
void Bar::doWork() { return m_impl->doWork(); }
, вам просто нужно определить сигнатуру в интерфейсе.Хорошо поняли :
Технология интерфейса лучше понимается каждым разработчиком C ++.
Производительность :
Интерфейс по быстродействию не хуже, чем у PImpl идиома, у обоих дополнительный доступ к памяти. Я предполагаю, что производительность такая же.
Ниже приведен псевдокод для иллюстрации моего вопроса:
// Forward declaration can help you avoid include BarImpl header, and those included in BarImpl header.
class BarImpl;
class Bar
{
public:
// public functions
void doWork();
private:
// You don't need to compile Bar.cpp after changing the implementation in BarImpl.cpp
BarImpl* m_impl;
};
Эту же цель можно реализовать с помощью интерфейса:
// Bar.h
class IBar
{
public:
virtual ~IBar(){}
// public functions
virtual void doWork() = 0;
};
// to only expose the interface instead of class name to caller
IBar* createObject();
Так какой смысл Пимпл?
источник
Impl
классе не нарушитABI
, но добавление публичной функции в интерфейсе сломаетABI
.unordered_set
), без PImpl, мне нужно#include <unordered_set>
вMyClass.h
. С PImpl мне нужно только включить его в.cpp
файл, а не в.h
файл, и, следовательно, все остальное, что включает его ...Я просто хочу обратиться к вашему выступлению. Если вы используете интерфейс, вы обязательно создали виртуальные функции, которые НЕ будут встроены оптимизатором компилятора. Функции PIMPL могут (и, вероятно, будут, потому что они такие короткие) встроены (возможно, более одного раза, если функция IMPL также мала). Вызов виртуальной функции нельзя оптимизировать, если вы не используете полную оптимизацию анализа программы, которая занимает очень много времени.
Если ваш класс PIMPL не используется с точки зрения производительности, этот момент не имеет большого значения, но ваше предположение о том, что производительность одинакова, справедливо только в некоторых ситуациях, но не во всех.
источник
Эта страница отвечает на ваш вопрос. Многие люди согласны с вашим утверждением. Использование Pimpl имеет следующие преимущества по сравнению с частными полями / членами.
Идиома Pimpl - это оптимизация во время компиляции, метод разрушения зависимостей. Вырубает большие заголовочные файлы. Это сводит ваш заголовок только к общедоступному интерфейсу. Длина заголовка важна в C ++, когда вы думаете о том, как это работает. #include эффективно объединяет заголовочный файл с исходным файлом, так что имейте в виду, что предварительно обработанные модули C ++ могут быть очень большими. Использование Pimpl может улучшить время компиляции.
Существуют и другие лучшие методы разрушения зависимостей, которые включают в себя улучшение вашего дизайна. Что представляют собой частные методы? Какова единственная ответственность? Должны ли они быть другого класса?
источник