например
// Implementation.
struct PrivatePoint {
void SomePrivateMethod();
double x;
double y;
}
struct Point : private PrivatePoint {
double DistanceTo(const Point& other) const;
}
Это похоже на Идиома. Это имеет два преимущества, которые мне действительно нравятся:
.
Point::DistanceTo(const Point& other) {
SomePrivateMethod();
double dx = other.x - x;
double dy = other.y - y;
return sqrt(dx * dx + dy * dy);
}
против
Point::DistanceTo(const Point& other) {
ptr->SomePrivateMethod();
double dx = other.ptr->x - ptr->x;
double dy = other.ptr->y - ptr->y;
return sqrt(dx * dx + dy * dy);
}
Ваше предложение имеет некоторые недостатки ….
Пользователи могут присоединиться к «приватному» классу.
Основная цель pimpl idiom — это брандмауэр компиляции, позволяющий указывать приватные элементы в файле реализации и, следовательно, изменять их, не касаясь заголовка и не вызывая / не инициируя перекомпиляцию клиента, в отличие от простого перекомпоновки, которая выполняется быстрее, и может даже не требовать каких-либо действий, связанных с клиентским приложением, если обновление выполняется для динамически загружаемой библиотеки. Вы теряете эти преимущества.
SomePrivateMethod является тестируемым. Если бы SomePrivateMethod вместо этого был объявлен закрытым в Point, вы бы не смогли вызвать его из тестов. Если вы объявите его как общедоступный или защищенный в Point, тесты смогут его вызывать, как и обычные пользователи Point.
Есть и другие удобные варианты, например: вы можете объявить о дружбе с тестовым кодом или использовать препроцессор для создания режима тестирования, который предоставляет данные.
Частное наследование очень похоже на композицию (и pimpl), но имеет ряд недостатков:
Вы должны сделать определение PrivatePoint видимым в общедоступном заголовке. Это вводит зависимость времени компиляции от PrivatePoint и требует, чтобы клиенты Point перекомпилировали каждый раз, когда PrivatePoint изменяется. С pimpl это не так, достаточно отправить объявление PrivatePoint следующим образом:
структура PrivatePoint;
Инкапсуляция неделя. Благодаря частному наследованию клиенты, расширяющие Point, могут реализовать собственную версию SomePrivateMethod (C ++ позволяет перезаписывать частные виртуальные методы). Это не проблема в вашем примере, но будет, если SomePrivateMethod был объявлен виртуальным
Если вы используете pimpl, вы также можете легко выполнить юнит-тест PrivatePoint.
нет, так как в любом случае вы должны опубликовать файл заголовка, который объявляет базовый класс. частное наследование защитит вас или ваших пользователей от нежелательного доступа к данным / методам.