繁体   English   中英

有没有办法,使用模板来防止类在C ++中派生

[英]Is there a way, using templates, to prevent a class from being derivable in C++

我需要阻止一个类派生,所以我想,这是Boost必须已经完成的事情。 我知道他们有一个不可复制的,他们必须有一个不可复制的......

想象一下,当我找不到它时,我感到惊讶......

这让我思考..必须有一个理由。 也许不可能使用模板..

我确定它是否很容易在升级库中。

我知道如何在不使用模板的情况下完成它,即使用带有私有构造函数的基类,即

class ThatCantBeDerived;  // Forward reference

class _NonDeriv
{
    _NonDeriv() {}
    friend class ThatCantBeDerived;
};

class ThatCantBeDerived : virtual public _NonDeriv
{
public:
    ThatCantBeDerived() :
      _NonDeriv()
    {
    }
};

或类似的东西..

也许它是导致问题的前向参考,或者可能没有可移植的方法来实现它。

无论哪种方式,我不确定为什么它不是在提升..

有任何想法吗?

在C ++中无法阻止派生 - 你无法阻止这种情况:

class A {};

class B : public A {};

但是,有几种方法可以防止B类对象的实例化 。这是值得的,值得商榷。 我更愿意记录A类不用于派生,并给它一个非虚拟析构函数。

另请注意,名称_NonDeriv在C ++中保留用于实现,所有名称都以下划线和大写字母开头。 您不能在自己的代码中创建此类名称。

根据当前规范,明确禁止“朋友”模板参数,因此模板化您的示例将使其不符合标准。 Boost可能不希望在其库中添加类似的东西。 我相信这个限制在Ox中正在放松,并且编译器有一些变通方法。

Adobe使用模板有一个不完美的解决方案。

问题在于,由于模板不能声明依赖于参数的朋友[*],它依赖于受保护的构造函数而不是私有。 这是一个部分解决方案,当有人错误地决定从您的类派生时它会触发编译器错误,但它不是一个完整的解决方案,因为有人故意强制继承。

template <typename SealedClass>
class seal
{
protected:
   seal() {}
};

class Sealed : private virtual seal<Sealed>
{
//...
};

class NaiveExtension : public Sealed { // fails
   NaiveExtension() {} // NaiveExtension cannot call seal<Sealed> constructor
};

class BreakingExtension : public Sealed, private virtual seal<Sealed> {
   BreakingExtension() : seal<Sealed>(), Sealed() {} // now it can
};

优点是它可以被模板化(adobe库实际上定义了一个宏,它将隐藏来自随意读者的'私有虚拟')。 缺点是它可以被打破。

然后,您可以随时执行C ++ FAQ建议的关于阻止某些功能的一些问题:

“我怎么能禁止人们......”: 写下评论不要这样做

“但我怎么能真正地抑制别人......”: 写一条评论:如果......你将被解雇

“但是,如果他们不遵循评论,我该如何实际阻止它?”: 解雇他们

[*]只要有可用,只要在编译器中实现,这个限制就会被即将推出的标准带走......

简单:

使所有构造函数都是私有的:
然后,nobdy可以从你那里衍生出来。 当然,这会增加一些问题,比如你不能实例化对象的变量,但是有使用公共静态成员方法和朋友的变通方法:

#include <memory>
class InstnaceCantDeriveFromMe;
class CantDeriveFromMe
{
    private:
        friend class InstnaceCantDeriveFromMe;
        CantDeriveFromMe()
        {}

    public:
        static std::auto_ptr<CantDeriveFromMe>  getDynamicObj()
        {
            return std::auto_ptr<CantDeriveFromMe>(new CantDeriveFromMe());
        }
};

class Plop: public CantDeriveFromMe
{
};

class InstnaceCantDeriveFromMe
{
    private:
        CantDeriveFromMe  instnace;
    public:
        CantDeriveFromMe& get() {return instnace;}
};

int main()
{
    std::auto_ptr<CantDeriveFromMe>  a =     CantDeriveFromMe::getDynamicObj();
    InstnaceCantDeriveFromMe         b;


    // This fails to compile:
    Plop                             c; 
}

也许可以使用CRTP将您的示例转换为模板 - 这是一种奇怪的重复模板模式:

template <typename T>
_NonDeriv
{
   _NonDeriv() {}
   friend class T;
};

class ThatCantBeDerived : virtual public _NonDeriv<ThatCantBeDerived>
{
public:
    ThatCantBeDerived() :
      _NonDeriv()
    {
    }
};

可能会工作......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM