我写了以下愚蠢的政策结构:
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(){}
执行此操作时,编译器会抱怨析构函数受到保护。我做错了什么?
答案 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()
。