阻止C ++中的类inheritance
最近我的一位朋友问我如何防止C ++中的类inheritance。 他想编辑失败。
我在想这个,find了3个答案。 不知道哪一个是最好的。
1)私人build构者
class CBase { public: static CBase* CreateInstance() { CBase* b1 = new CBase(); return b1; } private: CBase() { } CBase(CBase3) { } CBase& operator=(CBase&) { } };
2)使用CSealed基类,私有和虚拟inheritance
class CSealed { private: CSealed() { } friend class CBase; }; class CBase : virtual CSealed { public: CBase() { } };
3)使用CSealed基类,保护ctor和虚拟inheritance
class CSealed { protected: CSealed() { } }; class CBase : virtual CSealed { public: CBase() { } };
以上所有方法都确保CBase类不能被inheritance。 我的问题是:
1)哪个方法最好? 还有其他的方法吗?
2)方法2和3将不起作用,除非CSealed类被虚构地inheritance。 这是为什么 ? 这与vdisp ptr有什么关系?
PS:
上述程序是在MS C ++编译器(Visual Studio)中编译的。 参考: http : //www.codeguru.com/forum/archive/index.php/t-321146.html
从C ++ 11开始,您可以将final关键字添加到您的类中,例如
class CBase final { ...
我可以看到想要这样做的主要原因(以及我find这个问题的原因)是将一个类标记为非子类,所以您可以安全地使用非虚拟析构函数并完全避免使用一个vtable。
你正在经历扭曲,以防止进一步子类化。 为什么? logging类不可扩展的事实,使得dtor非虚拟化。 本着c的精神,如果有人真的想忽略你打算使用的方式,为什么要阻止它们呢? (我从来没有看到Java中的final
类/方法的要点)。
//Note: this class is not designed to be extended. (Hence the non-virtual dtor) struct DontExtened { DontExtened(); /*NOT VIRTUAL*/ ~DontExtened(); ... };
你不能阻止inheritance(在C ++ 11的final
关键字之前) – 你只能阻止inheritance类的实例化。 换句话说,没有办法预防:
class A { ... }; class B : public A { ... };
你可以做的最好的是防止typesB的对象被实例化。 既然如此,我build议你接受kts的build议,并logging下一个事实:A(或者其他)不是用来inheritance的,它是一个非虚拟的析构函数,并且没有其他的虚函数。
1)是一个品味的问题。 如果我看得很清楚的话,那么你的第二个和第三个解决scheme会在某些情况下从链接时间到编译时间移动错误,这通常会更好。
2)需要虚拟inheritance来强制将(虚拟)基类初始化为基类不再可达的派生类。
要回答你的问题,你不能从CBaseinheritance,因为在虚拟inheritance中,派生类需要直接访问虚拟inheritance的类。 在这种情况下,从CBase派生的类将需要直接访问CSealed,因为构造函数是私有的,所以它不能。
虽然我没有看到它的全部用处(即:停止inheritance),但是你可以使用模板进行推广(我不认为它在所有编译器上编译,但是它与MSVC一起编译)
template<class T> class CSealed { friend T; // Don't do friend class T because it won't compile CSealed() {} }; class CBase : private virtual CSealed<CBase> { };
如果可以的话,我会去第一个选项(私人构造函数)。 原因在于几乎所有有经验的C ++程序员都会一眼就能看出,并且能够识别出您正在尝试防止子类化。
可能还有其他更棘手的方法来防止子类化,但在这种情况下越简单越好。
class myclass; class my_lock { friend class myclass; private: my_lock() {} my_lock(const my_lock&) {} }; class myclass : public virtual my_lock { // ... public: myclass(); myclass(char*); // ... }; myclass m; class Der : public myclass { }; Der dd; // error Der::dd() cannot access // my_lock::my_lock(): private member
我在这里find了信用。 我在这里发布只是其他人可以轻松访问http://www.devx.com/tips/Tip/38482
详细阐述弗朗西斯的回答 :如果Bottom
类是从Middle
类inheritance而来的,它实际上是从Top
类inheritance的,那么大多数派生类( Bottom
)负责构造虚拟inheritance的基类( Top
)。 否则,在多重inheritance/死亡钻石的情况下(虚拟inheritance经常使用),编译器不会知道两个“中间”类中的哪一个应该构造单个基类。 Middle
构造函数对Top
的构造函数的调用因此在从Middle
构造Middle
被忽略:
class Top { public: Top() {} } class Middle: virtual public Top { public: Middle(): Top() {} // Top() is ignored if Middle constructed through Bottom() } class Bottom: public Middle { public: Bottom(): Middle(), Top() {} }
所以,在你的问题的方法2)或3)中, Bottom()
不能调用Top()
因为它在Middle
被私有inheritance(默认情况下,就像在你的代码中一样,但值得明确),因此Bottom
不可见。 ( 来源 )
另一个解决scheme:
template < class T > class SealedBase { protected: SealedBase() { } }; #define Sealed(_CLASS_NAME_) private virtual SealedBase<_CLASS_NAME_> #include "Sealed.h" class SomeClass : Sealed(Penguin) { };