如何通过 CRTP 实现修复破坏强封装规则?
How to fix breaking strong encapsulation rules with CRTP implementation?
我喜欢NVI idiom。
但有时我想减少 NVI 惯用法的 vftable 成本。
然后我尝试将 CRTP 应用到 NVI,如下所示。
template<typename E>
class unary_interface {
public:
virtual ~unary_interface() = default;
public:
double operator()(const double x) const
{
return static_cast<const E&>(*this).apply(x); //occurs compile error!!!
}
};
class square : public unary_interface<square> {
private:
double apply(const double x) const
{
return x * x;
}
};
但是这段代码出现编译错误
如果我将私有字段中的应用函数更改为 public,封装将被破坏。
我想到不透明的别名可以解决这个问题,如下所示。
template<typename E>
class unary_interface {
public:
virtual ~unary_interface() = default;
protected:
class input_type {
public:
explicit input_type(const double x) : _x(x) {}
operator double() const
{
return _x;
}
private:
const double _x;
};
public:
double operator()(const double x) const
{
return static_cast<const E&>(*this).apply(input_type(x));
}
};
class square : public unary_interface<square> {
using base_type = unary_interface<square>;
public:
double apply(const base_type::input_type& d) const
{
const double x = static_cast<const double>(d);
return x * x;
}
};
此设计继续禁止访问除 unary_interface 的 operator() 之外的应用函数。
乍一看 "apply function" 暴露给用户代码,但应用函数只接受受保护的不透明别名类型,该别名类型定义在 unary_interface 的受保护字段中。
我认为这种组合非常好,并且在保持强大封装的同时降低了虚函数成本。
这个idea有没有我没发现的缺陷,你有没有给这个设计具体的名字?
But this code occurs compile error.
...
At first glance "apply function" is exposed to user code, but apply function is accept only protected opaque alias type that is defined on unary_interface in protected field. I think that this combination is very good and reduce virtual function cost with keeping strong encapsulation.
您可以使用 friend
轻松解决您的 强封装 困境(在这种情况下,它不会附带任何 negative consequences):
class square : public unary_interface<square> {
friend class unary_interface<square>; // <<<
double apply(const double x) const // <<< Keep apply() private
{
return x * x;
}
};
无需偏离使用 protected input_type
。
请参阅Live Demo。
Does this idea has any defect that I can not find out, and do you have a specific name for this design?
嗯,缺陷是 过于复杂 情况并向最终用户呈现他们实际上无法使用的 public 功能。
我不知道那个反模式是否已经被识别和命名。通过声明无法在 public API.
处有效使用的承诺,以某种方式滥用了 public
接口区域
我喜欢NVI idiom。
但有时我想减少 NVI 惯用法的 vftable 成本。 然后我尝试将 CRTP 应用到 NVI,如下所示。
template<typename E>
class unary_interface {
public:
virtual ~unary_interface() = default;
public:
double operator()(const double x) const
{
return static_cast<const E&>(*this).apply(x); //occurs compile error!!!
}
};
class square : public unary_interface<square> {
private:
double apply(const double x) const
{
return x * x;
}
};
但是这段代码出现编译错误
如果我将私有字段中的应用函数更改为 public,封装将被破坏。 我想到不透明的别名可以解决这个问题,如下所示。
template<typename E>
class unary_interface {
public:
virtual ~unary_interface() = default;
protected:
class input_type {
public:
explicit input_type(const double x) : _x(x) {}
operator double() const
{
return _x;
}
private:
const double _x;
};
public:
double operator()(const double x) const
{
return static_cast<const E&>(*this).apply(input_type(x));
}
};
class square : public unary_interface<square> {
using base_type = unary_interface<square>;
public:
double apply(const base_type::input_type& d) const
{
const double x = static_cast<const double>(d);
return x * x;
}
};
此设计继续禁止访问除 unary_interface 的 operator() 之外的应用函数。
乍一看 "apply function" 暴露给用户代码,但应用函数只接受受保护的不透明别名类型,该别名类型定义在 unary_interface 的受保护字段中。 我认为这种组合非常好,并且在保持强大封装的同时降低了虚函数成本。
这个idea有没有我没发现的缺陷,你有没有给这个设计具体的名字?
But this code occurs compile error.
...
At first glance "apply function" is exposed to user code, but apply function is accept only protected opaque alias type that is defined on unary_interface in protected field. I think that this combination is very good and reduce virtual function cost with keeping strong encapsulation.
您可以使用 friend
轻松解决您的 强封装 困境(在这种情况下,它不会附带任何 negative consequences):
class square : public unary_interface<square> {
friend class unary_interface<square>; // <<<
double apply(const double x) const // <<< Keep apply() private
{
return x * x;
}
};
无需偏离使用 protected input_type
。
请参阅Live Demo。
Does this idea has any defect that I can not find out, and do you have a specific name for this design?
嗯,缺陷是 过于复杂 情况并向最终用户呈现他们实际上无法使用的 public 功能。
我不知道那个反模式是否已经被识别和命名。通过声明无法在 public API.
处有效使用的承诺,以某种方式滥用了public
接口区域