是否有可能在编译时禁止从类派生?

Seb*_*anK 11 c++

根据"C++编码标准"第32项中的描述,我有一个值类.简而言之,这意味着它提供了值语义,并且没有任何虚方法.

我不希望一个类派生自这个类.除了其他人之外,一个原因是它有一个公共的非虚拟析构函数.但是,基类应该具有公共和虚拟或受保护和非虚拟的析构函数.

我不知道写值类的可能性,因此不可能从中派生出来.我想在编译时禁止它.是否有任何已知的成语可以做到这一点?如果没有,或许在即将到来的C++ 0x中有一些新的可能性?还是有充分的理由说没有这种可能性?

Sim*_*ens 25

Bjarne Stroustrup 在这里写过这篇文章.


链接中的相关位:

我可以阻止那些来自我班级的人吗?

是的,但你为什么这么想?有两个常见的答案:

  • 为了效率:避免我的函数调用是虚拟的.
  • 为了安全:确保我的类不被用作基类(例如,确保我可以复制对象而不用担心切片)

根据我的经验,效率原因通常是错位的恐惧.在C++中,与使用普通函数调用的替代解决方案相比,虚函数调用非常快,以至于它们对使用虚函数设计的类的实际使用不会产生可测量的运行时开销.请注意,虚函数调用机制通常仅在通过指针或引用进行调用时使用.当直接为命名对象调用函数时,虚拟函数类开销很容易被优化掉.

如果确实需要"封顶"类层次结构以避免虚函数调用,那么可能会首先询问为什么这些函数是虚拟的.我已经看到了一些例子,其中性能关键功能已经被虚拟化,没有任何理由,只是因为"这就是我们通常的做法".

此问题的另一个变体,如何根据逻辑原因防止派生,有一个解决方案.不幸的是,这个解决方案并不漂亮.它依赖于层次结构中派生程度最高的类必须构造虚拟基础的事实.例如:

class Usable;

class Usable_lock {
    friend class Usable;
private:
    Usable_lock() {}
    Usable_lock(const Usable_lock&) {}
};

class Usable : public virtual Usable_lock {
    // ...
public:
    Usable();
    Usable(char*);
    // ...
};

Usable a;

class DD : public Usable { };

DD dd;  // error: DD::DD() cannot access
        // Usable_lock::Usable_lock(): private  member
Run Code Online (Sandbox Code Playgroud)

(来自D&E sec 11.4.3).

  • @Motti:我非常喜欢你的答案 - 我给它+1了.根据他的要求,它可能是一个更好的解决方案.Bjarnes有点复杂,如果你真正想做的就是阻止某人使用他们的类型代替你的类型.我认为重要的是要考虑为什么你试图阻止推导,并且它真的实现了任何有用的东西. (2认同)
  • @SebastianK:"它依赖于层次结构中派生程度最高的类必须构建虚拟基础的事实".有趣的是我在西蒙面前给出了同样的答案并且没有得到任何选票.我的Upvote也是:) (2认同)
  • @SebastianK:就像the_drow所说的那样,通过使基类成为虚拟,最需要的类需要构造它,但在这种情况下不能因为构造函数是私有的.@The_drow:这是名人效应.提到Stroustrup额外的信用= :) (2认同)

Mot*_*tti 8

如果您愿意只允许通过工厂方法创建类,则可以使用私有构造函数.

class underivable {
    underivable() { }
    underivable(const underivable&); // not implemented
    underivable& operator=(const underivable&); // not implemented
public:
    static underivable create() { return underivable(); }
};
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这并不能阻止推导.除了通过工厂之外,它仅仅防止派生类型的实例化.如果你能真正实现pprevent派生会很好,但据我所知,你做不到. (3认同)

Ton*_*ony 6

即使问题没有标记为C++ 11,对于到达此处的人来说,应该提到C++ 11支持新的上下文标识符final.请参阅维基页面