Имеете дело с защищенным / частным конструктором / деструктором для разработки CRTP?

Рассмотрим следующий код:

#include <iostream>
#include <type_traits>

// Abstract base class
template<class Crtp>
class Base
{
// Lifecycle
public: // MARKER 1
Base(const int x) :  _x(x) {}
protected: // MARKER 2
~Base() {}

// Functions
public:
int get() {return _x;}
Crtp& set(const int x) {_x = x; return static_cast<Crtp&>(*this);}

// Data members
protected:
int _x;
};

// Derived class
class Derived
: public Base<Derived>
{
// Lifecycle
public:
Derived(const int x) : Base<Derived>(x) {}
~Derived() {}
};

// Main
int main()
{
Derived d(5);
std::cout<<d.set(42).get()<<std::endl;
return 0;
}

Если я хочу публичное наследство Derived от Baseи если я не хочу виртуальный деструктор в базовом классе, какие ключевые слова будут наилучшими для конструктора (MARKER 1) и деструктор (MARKER 2) из Base гарантировать, что ничего плохого не может случиться?

3

Решение

Какой бы стиль программирования вы ни использовали, вы всегда можете сделать что-то плохое: даже если вы следуете лучшим из лучших практических рекомендаций. Это что-то физическое за этим (и связано с невозможностью уменьшить глобальную энтрофию)

Тем не менее, не путайте «классическую ООП» (методологию) с C ++ (язык), наследованием ООП (отношение) с наследованием С ++ (механизм агрегации) и полиморфизмом ООП (модель) со средой выполнения C ++ и статическим полиморфизмом ( диспетчерский механизм).

Хотя имена иногда совпадают, C ++ — вещи не обязательно должны обслуживать OOP.

Публичное наследование от базы с некоторыми не виртуальными методами нормально. и деструктор не особенный: просто не вызывайте delete на базе CRTP.

В отличие от классического ООП, база CRTP имеет различный тип для каждого из производных, поэтому наличие «указателя на базу» не имеет смысла, поскольку нет «указателя на общий тип». И, следовательно, риск назвать «delete pbase» очень ограничен.

«Парадигма protected-dtor» действительна только в том случае, если вы программируете OOP-наследование, используя наследование C ++ для объекта, управляемого (и удаленного) через полиморфизм на основе указателей. Если вы следуете другим парадигмам, эти правила не должны восприниматься буквально.

В вашем случае, защищенный dtor просто отказывает вам в создании Base<Derived> в стеке и вызывать delete на базе *. Что-то, что вы никогда не будете делать, так как Base без «Dervied» не имеет смысла существовать, и иметь Base<Derived>* не имеет смысла, так как вы можете иметь только Derived*Следовательно, наличие публичного ctor и dtor не создает особого беспорядка.

Но вы можете даже сделать противоположный выбор, чтобы защитить и ctor, и dtor, поскольку вы никогда не создадите Base в одиночку, так как ему всегда нужен производный тип, чтобы быть известным.

Из-за особой конструкции CRTP все классические ООП-вещи приводят к своего рода «равнодушному равновесию», так как больше нет «опасного варианта использования».

Вы можете использовать их или нет, но ничего плохого не случится. Нет, если вы используете объект так, как они были предназначены для использования.

3

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

Пока ваш код работает, я считаю странным отметить деструктор а не конструктор как protected, Обычно я рассуждаю так, что вы хотите предотвратить случайное программирование создание базовый объект CRTP. Конечно, все сводится к одному и тому же, но это вряд ли канонический код.

Единственное, что предотвращает ваш код, — это случайное удаление объекта CRTP через базовый указатель — то есть такой случай:

Base<Derived>* base = new Derived;
delete base;

Но это очень искусственная ситуация, которая не возникнет в реальном коде, поскольку CRTP просто не должен использоваться таким образом. База CRTP — это деталь реализации, которая должна быть полностью скрыта от клиентского кода.

Таким образом, мой рецепт для этой ситуации будет:

  • Определите защищенный конструктор.
  • Не определяйте деструктор — или, если требуется для семантики CRTP, определите его как public (и не виртуальный).
1

Нет проблем, поскольку деструктор защищен, это означает, что клиентский код не может удалить указатель на Base, поэтому нет проблем с деструктором Base, который не является виртуальным.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector