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

4

2 回答 2

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() 在该对象上调用(它不是 type League)。

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

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

于 2013-05-22T21:59:54.817 回答
1
Policy<TT>().printLeague();

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

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

于 2013-05-22T22:01:46.610 回答