我喜欢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;
}
};
但是这段代码出现了编译错误。
如果我将私有字段中的apply函数更改为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函数。
乍一看“应用功能”暴露给用户代码,但应用功能只接受受保护字段中unary_interface上定义的受保护的不透明别名类型。 我认为这种组合非常好,并且通过保持强大的封装来降低虚拟功能成本。
这个想法是否有任何我无法找到的缺陷,你有这个设计的具体名称吗?
答案 0 :(得分:3)
但是这段代码出现编译错误 ...
乍一看“应用函数”暴露给用户代码,但应用函数只接受受保护字段中unary_interface上定义的受保护的不透明别名类型。我认为这种组合非常好,并且通过保持强大的封装来降低虚拟功能成本。
您可以使用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。
这个想法是否有任何我无法找到的缺陷,你有这个设计的具体名称吗?
嗯,缺点是过度复杂化情况并向最终用户展示他们实际上无法使用的公共功能。
我不知道是否已经识别并命名了反模式。通过声明无法在公共API中有效使用的承诺,以某种方式滥用public
接口区域。