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

时间:2013-05-22 21:53:36

标签: c++ templates destructor

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

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写道: 除非策略类定义了虚拟析构函数,否则将delete应用于指向策略类的指针具有未定义的行为 。他解释了在从策略类派生时不对策略或受保护(或私有)继承使用虚拟析构函数的原因,他建议 策略应该使用的轻量级,有效的解决方案是定义非虚拟保护析 即可。问题是,当我尝试使用~SuperLeague(){}执行此操作时,编译器会抱怨析构函数受到保护。我做错了什么?

2 个答案:

答案 0 :(得分:2)

您不应该在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在访问对象时(或取消引用引用或对象)使基类成员可以从派生类访问指向对象的指针)相同派生类的 (在您的情况下为League)。

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

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

  

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

答案 1 :(得分:1)

Policy<TT>().printLeague();

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

由于Policy<TT>是基类,因此只需直接调用printLeague()