Это хорошая идея использовать частное наследование, чтобы скрыть реализацию?

например

// Implementation.
struct PrivatePoint {
void SomePrivateMethod();

double x;
double y;
}

struct Point : private PrivatePoint {
double DistanceTo(const Point& other) const;
}

Это похоже на Идиома. Это имеет два преимущества, которые мне действительно нравятся:

  1. SomePrivateMethod является тестируемым. Если бы SomePrivateMethod вместо этого был объявлен закрытым в Point, вы бы не смогли вызвать его из тестов. Если вы объявите его как общедоступный или защищенный в Point, тесты смогут его вызывать, как и обычные пользователи Point.
  2. Доступ к частным данным легче читать и писать по сравнению с тем, как вы делаете это в идиоме Pimpl, потому что вам не нужно проходить через указатель, например

.

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);
}

2

Решение

Ваше предложение имеет некоторые недостатки ….

Пользователи могут присоединиться к «приватному» классу.

Основная цель pimpl idiom — это брандмауэр компиляции, позволяющий указывать приватные элементы в файле реализации и, следовательно, изменять их, не касаясь заголовка и не вызывая / не инициируя перекомпиляцию клиента, в отличие от простого перекомпоновки, которая выполняется быстрее, и может даже не требовать каких-либо действий, связанных с клиентским приложением, если обновление выполняется для динамически загружаемой библиотеки. Вы теряете эти преимущества.

SomePrivateMethod является тестируемым. Если бы SomePrivateMethod вместо этого был объявлен закрытым в Point, вы бы не смогли вызвать его из тестов. Если вы объявите его как общедоступный или защищенный в Point, тесты смогут его вызывать, как и обычные пользователи Point.

Есть и другие удобные варианты, например: вы можете объявить о дружбе с тестовым кодом или использовать препроцессор для создания режима тестирования, который предоставляет данные.

2

Другие решения

Частное наследование очень похоже на композицию (и pimpl), но имеет ряд недостатков:

  1. Вы должны сделать определение PrivatePoint видимым в общедоступном заголовке. Это вводит зависимость времени компиляции от PrivatePoint и требует, чтобы клиенты Point перекомпилировали каждый раз, когда PrivatePoint изменяется. С pimpl это не так, достаточно отправить объявление PrivatePoint следующим образом:
    структура PrivatePoint;

  2. Инкапсуляция неделя. Благодаря частному наследованию клиенты, расширяющие Point, могут реализовать собственную версию SomePrivateMethod (C ++ позволяет перезаписывать частные виртуальные методы). Это не проблема в вашем примере, но будет, если SomePrivateMethod был объявлен виртуальным

Если вы используете pimpl, вы также можете легко выполнить юнит-тест PrivatePoint.

1

нет, так как в любом случае вы должны опубликовать файл заголовка, который объявляет базовый класс. частное наследование защитит вас или ваших пользователей от нежелательного доступа к данным / методам.

0
По вопросам рекламы [email protected]