Оператор преобразования политики против частного деструктора в классе на основе политики

В 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?

2

Решение

Проблема в том, что вы не можете создавать объекты с защищенными деструкторами, кроме как из производного класса. Поэтому оператор преобразования, создающий такие временные данные, запрещен. Один из способов обойти это сделать 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";
}

Живой пример.

Обратите внимание, что защищенные деструкторы и публичное наследование действительно рекомендуются, но особенно рекомендуется безопасно использовать «обогащенные» (т.е. с сохранением состояния) политики. Для политик без гражданства можно также использовать защищенное наследование и публичные деструкторы. Для этих политик операторы преобразования могут генерировать временные данные просто отлично.

1

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


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