В Modern C++ Design: Generic Programming and Design Patterns Applied
Андрей Александреску выступает за защиту деструктора политики:
Поскольку деструктор защищен, только производные классы могут уничтожать объекты политики, поэтому это невозможно
посторонние, чтобы применить удаление к указателю на класс политики. Деструктор, однако, не является виртуальным, поэтому есть
нет размера или скорости
Но позже он пишет следующий параграф о политике совместимости:
Как видите, у вас есть двусторонняя гибкость в реализации конверсий между политиками. Вы можете
реализовать конструктор преобразования в левой части, или вы можете реализовать оператор преобразования в
правая сторона.
Допустим, у нас есть 2 политики:
class First{
public:
First() = default;
First(const First&) = default;
protected:
~First() = default;
};
class Second{
public:
explicit operator First() const {
return //what???
}
Second() = default;
Second(const Second&) = default;
Second(const First& ) {};
protected:
~Second() = default;
};
Как создать оператор преобразования из политики Second в политику First без создания временного объекта типа First?
Проблема в том, что вы не можете создавать объекты с защищенными деструкторами, кроме как из производного класса. Поэтому оператор преобразования, создающий такие временные данные, запрещен. Один из способов обойти это сделать First
а также Second
принимает друг друга через explicit
конструкторы:
#include <iostream>
class First;
class Second;
class First
{
public:
First() = default;
First(const First&) = default;
explicit First(const Second&);
int value() const { return x; }
protected:
~First() = default;
private:
int x = 1;
};
class Second
{
public:
Second() = default;
Second(const Second&) = default;
explicit Second(const First&);
int value() const { return x; }
protected:
~Second() = default;
private:
int x = 2;
};
First::First(const Second& s): x(s.value()) {}
Second::Second(const First& f): x(f.value()) {}
Затем вы можете создать шаблон класса хоста Host<Policy>
который имеет шаблонный конструктор преобразования, который преобразует политики Policy
и произвольно U
template<class Policy>
class Host
:
public Policy
{
public:
Host() = default;
template<class U>
Host(Host<U> const& other)
:
Policy(other)
{}
};
int main()
{
Host<First> h1;
Host<Second> h2;
Host<Second> h3(h1);
Host<First> h4(h2);
std::cout << h1.value() << "\n";
std::cout << h2.value() << "\n";
std::cout << h3.value() << "\n";
std::cout << h4.value() << "\n";
}
Обратите внимание, что защищенные деструкторы и публичное наследование действительно рекомендуются, но особенно рекомендуется безопасно использовать «обогащенные» (т.е. с сохранением состояния) политики. Для политик без гражданства можно также использовать защищенное наследование и публичные деструкторы. Для этих политик операторы преобразования могут генерировать временные данные просто отлично.