Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用CRTP实现修复破坏强封装规则的问题?_C++_Encapsulation_Crtp - Fatal编程技术网

C++ 如何使用CRTP实现修复破坏强封装规则的问题?

C++ 如何使用CRTP实现修复破坏强封装规则的问题?,c++,encapsulation,crtp,C++,Encapsulation,Crtp,我喜欢 但有时我想从NVI习惯用法中降低vftable成本。 然后我试着向NVI申请如下 template<typename E> class unary_interface { public: virtual ~unary_interface() = default; public: double operator()(const double x) const { return static_cast<const E&>

我喜欢

但有时我想从NVI习惯用法中降低vftable成本。 然后我试着向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;
    }
};
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;
    }
};
模板
类一元接口{
公众:
虚拟~一元_接口()=默认值;
公众:
双运算符()(常数双x)常数
{
返回static_cast(*this).apply(x);//发生编译错误!!!
}
};
类方:公共一元接口{
私人:
双应用(常数双x)常数
{
返回x*x;
}
};
但此代码发生编译错误

若我将private字段中的apply函数更改为public,封装就会被破坏。 我有一个想法,不透明别名解决这个问题如下

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;
    }
};
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;
    }
};
模板
类一元接口{
公众:
虚拟~一元_接口()=默认值;
受保护的:
类输入类型{
公众:
显式输入类型(const double x):\ux(x){}
运算符double()常量
{
返回x;
}
私人:
常数双x;
};
公众:
双运算符()(常数双x)常数
{
返回static_cast(*this).apply(输入_类型(x));
}
};
类方:公共一元接口{
使用基本类型=一元接口;
公众:
双应用(常量基本类型::输入类型和d)常量
{
const double x=静态施法(d);
返回x*x;
}
};
本设计一直禁止从一元_接口的运算符()访问应用函数

乍一看,“应用函数”是向用户代码公开的,但应用函数是仅接受受保护的不透明别名类型,它是在受保护字段的一元_接口上定义的。 我认为这种组合非常好,并且在保持强大封装的情况下降低了虚拟函数的成本

这个想法是否有我找不到的缺陷,你对这个设计有具体的名字吗

但此代码出现编译错误。

乍一看,“应用函数”是向用户代码公开的,但应用函数是仅接受受保护的不透明别名类型,它是在受保护字段的一元_接口上定义的。我认为这种组合非常好,并且在保持强大封装的情况下降低了虚拟函数的成本

您可以使用
friend
(在这种情况下,它不会附带任何功能)轻松解决您的强封装难题:

class square:公共一元接口{

friend class一元_interface;//谢谢你的回复。我同意复杂的设计是不好的。起初,我有了使用friend的想法。我错误地认为friend总是不受欢迎的,但我认为friend在特定情况下是非常有效的工具,多亏了你。@YusukeMori很高兴能提供帮助。你可能需要为这个问题找到一个更好的标题。@YusukeMori打开。但一般来说,它是相当有用的。当您公开
private
内部类句柄时,有一种不同的情况,它可以与
public
API中的
auto
一起使用。