根据“C++编码标准”第32条中的描述,我有一个值类。简而言之,这意味着它提供了值语义,并且没有任何虚拟方法。是否有可能在编译时禁止从类中派生?
我不想让一个类从这个类派生。除此之外,其中一个原因是它具有公共的非虚构析构函数。但是基类应该有一个公共和虚拟的析构函数,或者是非虚拟的。
我不知道编写值类的可能性,以至于不可能从它派生出来。我想在编译时禁止它。是否有任何已知的习惯用法呢?如果不是,那么即将到来的C++ 0x也许有一些新的可能性?还是有没有这种可能性的充分理由?
根据“C++编码标准”第32条中的描述,我有一个值类。简而言之,这意味着它提供了值语义,并且没有任何虚拟方法。是否有可能在编译时禁止从类中派生?
我不想让一个类从这个类派生。除此之外,其中一个原因是它具有公共的非虚构析构函数。但是基类应该有一个公共和虚拟的析构函数,或者是非虚拟的。
我不知道编写值类的可能性,以至于不可能从它派生出来。我想在编译时禁止它。是否有任何已知的习惯用法呢?如果不是,那么即将到来的C++ 0x也许有一些新的可能性?还是有没有这种可能性的充分理由?
即使问题没有标记为C++ 11,人谁得到这里应该提到的是C++ 11支持新的上下文标识符final
。见wiki page
如果您只允许通过工厂方法创建类,则可以使用私有构造函数。
class underivable {
underivable() { }
underivable(const underivable&); // not implemented
underivable& operator=(const underivable&); // not implemented
public:
static underivable create() { return underivable(); }
};
了Bjarne Stroustrup的写关于这个here。
从链接的相关位:
我可以阻止人们从我的类派生?
是的,但你为什么要?有两个常见的答案:
用作 基类,以我的经验,效率理由通常是错放的恐惧。在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
(从D&E秒11.4.3)。
嗯,我有一个类似的问题。这是在SO上发布的here。这个问题是另一回事。即只允许派生你允许的类。检查它是否解决您的问题。
这在编译时间完成。
好好看看here。
这真的很酷,但它是一个黑客。
不知道为什么stdlib不会用它自己的容器做到这一点。
此解决方案不起作用,但我将其作为不做的一个示例。
我没有使用C++有一段时间了,但据我记得,你得到你想通过析构函数私人的东西。
UPDATE:
在Visual Studio 2005中,你会得到警告或错误。检查了下面的代码:
class A
{
public:
A(){}
private:
~A(){}
};
class B : A
{
};
现在,
B B;
会产生一个错误 “错误C2248: 'A ::〜A':不能访问类 'A' 声明私有成员”
而
B *b = new B();
会产生警告“警告C4624: 'B':析构函数无法生成,因为基类析构函数无法访问“。
它看起来像一个半解决方案,但正如orsogufo指出的,这样做会导致A类不可用。离开答案
我一般会做到这一点,如下所示:
// This class is *not* suitable for use as a base class
评论之后,在头和/或文档。如果你的班级的客户不遵守包装上的说明,那么在C++中,他们可能会出现未定义的行为。未经许可而派生只是这种情况的特例。他们应该使用组合。
顺便说一句,这有点误导:“一个基类应该有一个公共的,虚拟的或者受保护的和非虚拟的析构函数”。
对于要用作运行时多态性基类的类也是如此。但是,如果派生类永远不会通过指向基类类型的指针来引用,那就没有必要。具有仅用于静态多态性的值类型可能是合理的,例如模拟动态绑定。令人困惑的是,继承可以用于C++中的不同目的,需要基类的不同支持。这意味着,虽然你不想动态多态性与你的类,它可能仍然是良好的创建派生类提供他们正确使用。
啊,这可能是我的类的静态工厂方法来保持东西放在一起?听起来很不错。 – SebastianK 2009-06-16 11:38:07
不幸的是,这并不能阻止派生。它只是防止派生类型的安装,除了通过工厂。如果你真的可以预防派生,那就太好了,但据我所知,你不能。 – 2009-06-16 11:43:41
实用的方式是不能实例化派生类型的对象,并且根本无法派生(访问受保护的静态成员??) – Motti 2009-06-16 18:02:41