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

时间:2010-01-21 17:53:21

标签: c++ boost

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

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

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

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

我知道如何不使用模板,即使用带有私有构造函数的基类,即

class ThatCantBeDerived;  // Forward reference

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

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

或者像这样......

也许这是导致问题的前向引用,或者可能没有可行的方法来实现它..

无论哪种方式,我都不确定为什么它没有加强..

有什么想法吗?

6 个答案:

答案 0 :(得分:7)

答案 1 :(得分:3)

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

class A {};

class B : public A {};

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

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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

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

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建议:

  

'如何禁止人们......':写评论不要这样做

     

'但是我如何才能真正抑制其他人...':写一条评论:如果......你会被解雇

     

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

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

答案 4 :(得分:1)

易:

将所有构造函数设为私有:
然后,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; 
}

答案 5 :(得分:0)

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

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

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

可能会工作......