2

Modern C++ Design: Generic Programming and Design Patterns AppliedAndrei Alexandrescu 中,提倡保护策略的析构函数:

因为析构函数是受保护的,只有派生类才能销毁策略对象,所以外人不可能对指向策略类的指针应用 delete。然而,析构函数不是虚拟的,因此没有大小或速度开销

但后来,他写了以下关于政策兼容性的段落:

如您所见,您在实施策略之间的转换方面具有双向灵活性。您可以在左侧实现转换构造函数,也可以在右侧实现转换运算符。

假设我们有 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;
};

如何在不构造 First 类型的临时对象的情况下创建从策略 Second 到 Policy First 的转换运算符?

4

1 回答 1

1

问题是您不能使用受保护的析构函数创建对象,除非是派生类。因此,禁止创建此类临时对象的转换运算符。解决它的一种方法是通过构造函数相互制造First和接受:Secondexplicit

#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";
}

活生生的例子

请注意,确实建议使用受保护的析构函数和公共继承,但特别建议它们安全地使用“丰富的”(即有状态的)策略。对于无状态策略,还可以使用受保护的继承和公共析构函数。对于这些策略,转换运算符可以很好地生成临时变量。

于 2014-08-26T11:24:14.280 回答