首页 文章

C语言中受保护的策略类析构函数

提问于
浏览
0

我写了以下愚蠢的政策结构:

template
<typename T>
struct SuperLeague
{
public:
  void printLeague(){std::cout << "SuperLegue" << std::endl;};
protected:
  //~SuperLeague(){}
};

和主持人类

template
<typename TT,template <typename C> class Policy>
class League: public Policy<TT>
{
public:
  void fun()
  {
    Policy<TT>().printLeague();
  }
};

我的主要是

int main()
{
  League<int,SuperLeague> k;
  League<int,SuperLeague> kk;
  k.fun();
  kk.printLeague();
  League<int,SuperLeague> *kkk=new League<int,SuperLeague>();
  kkk->fun();
  //delete kkk;
};

直到这里,一切正常 . 输出是:

SuperLegue
SuperLegue
SuperLegue

在他的一本书中,Andrei Alexandrescu写道: Unless the policy class defines a virtual destructor, applying delete to a pointer to the policy class has undefined behavior . 他解释了在从策略类派生时不对策略或受保护(或私有)继承使用虚拟析构函数的原因,并建议 The lightweight, effective solution that policies should use is to define a nonvirtual protected destructor . 问题是当我尝试使用 ~SuperLeague(){} 时,编译器抱怨析构函数受到保护 . 我做错了什么?

2 回答

  • 1

    您不应该在 League::fun() 中创建临时策略对象 . 由于 League 模板的实例派生自 Policy 模板的相应实例,因此它继承了 printLeague() 函数:

    template
    <typename TT,template <typename C> class Policy>
    class League: public Policy<TT>
    {
    public:
      void fun()
      {
        Policy<TT>::printLeague();
    //  ^^^^^^^^^^^^^^^^^^^^^^^^^^
      }
    };
    

    当您声明析构函数 protected 时,您的解决方案无法编译的原因是 protected 在访问对象时(或取消引用指向对象的引用或指针)时,可以从派生类访问基类成员 of the same derived class (在您的情况下为 League ) .

    在您的示例中不是这种情况,您在该示例中创建 Policy<TT> 类型的临时对象并在该对象(不是 League 类型)上调用 printLeague() .

    根据C 11标准第11.4 / 1段:

    当非静态数据成员或非静态成员函数是其命名类的受保护成员时,将应用超出第11章中所述之外的其他访问检查(11.2) . 如前所述,授予对受保护成员的访问权限,因为引用发生在朋友或某个类C的成员中 . 如果访问要形成指向成员的指针(5.3.1),则嵌套名称说明符应表示C或者从C派生的类 . 所有其他访问涉及(可能是隐式的)对象表达式(5.2.5) . 在这种情况下,对象表达式的类应为C或从C派生的类 .

  • 2
    Policy<TT>().printLeague();
    

    这将创建一个 Policy<TT> 类型的对象,在该对象上调用 printLeague() ,然后销毁该对象 . 编译器抱怨破坏对象,因为析构函数受到保护 .

    由于 Policy<TT> 是基类,只需直接调用 printLeague() 即可 .

相关问题