防止 C++ 中的类继承
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2184133/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Prevent class inheritance in C++
提问by ring0
Recently one of my friend asked me how to prevent class inheritance in C++. He wanted the compilation to fail.
最近我的一位朋友问我如何防止 C++ 中的类继承。他希望编译失败。
I was thinking about it and found 3 answers. Not sure which is the best one.
我正在考虑它并找到了3个答案。不确定哪个是最好的。
1) Private Constructor(s)
1) 私有构造函数
class CBase
{
public:
static CBase* CreateInstance()
{
CBase* b1 = new CBase();
return b1;
}
private:
CBase() { }
CBase(CBase3) { }
CBase& operator=(CBase&) { }
};
2) Using CSealed base class, private ctor & virtual inheritance
2) 使用 CSealed 基类、私有构造函数和虚拟继承
class CSealed
{
private:
CSealed() {
}
friend class CBase;
};
class CBase : virtual CSealed
{
public:
CBase() {
}
};
3) Using a CSealed base class, protected ctor & virtual inheritance
3) 使用 CSealed 基类、受保护的构造函数和虚拟继承
class CSealed
{
protected:
CSealed() {
}
};
class CBase : virtual CSealed
{
public:
CBase() {
}
};
All the above methods make sure that CBase class cannot be inherited further. My Question is:
以上所有方法都确保 CBase 类不能被进一步继承。我的问题是:
1) Which is the best method ? Any other methods available ?
1)哪种方法最好?还有其他可用的方法吗?
2) Method 2 & 3 will not work unless the CSealed class is inherited virutally. Why is that ? Does it have anything to do with vdisp ptr ??
2) 方法 2 和 3 将不起作用,除非 CSealed 类是虚拟继承的。这是为什么 ?它与 vdisp ptr 有什么关系吗??
PS:
PS:
The above program was compiled in MS C++ compiler (Visual Studio). reference : http://www.codeguru.com/forum/archive/index.php/t-321146.html
上述程序是在 MS C++ 编译器 (Visual Studio) 中编译的。参考:http: //www.codeguru.com/forum/archive/index.php/t-321146.html
回答by Peter N Lewis
As of C++11, you can add the final keyword to your class, eg
从 C++11 开始,您可以将 final 关键字添加到您的类中,例如
class CBase final
{
...
The main reason I can see for wanting to do this (and the reason I came looking for this question) is to mark a class as non subclassable so you can safely use a non-virtual destructor and avoid a vtable altogether.
我可以看到想要这样做的主要原因(以及我来寻找这个问题的原因)是将类标记为不可子类,以便您可以安全地使用非虚拟析构函数并完全避免使用 vtable。
回答by ring0
You can't prevent inheritance (before C++11's final
keyword) - you can only prevent instantiation of inherited classes. In other words, there is no way of preventing:
你不能阻止继承(在 C++11 的final
关键字之前)——你只能阻止继承类的实例化。换句话说,没有办法防止:
class A { ... };
class B : public A { ... };
The best you can do is prevent objects of type B from being instantiated. That being the case, I suggest you take kts's advice and document the fact that A (or whatever) is not intended to be used for inheritance, give it a non-virtual destructor, and no other virtual functions, and leave it at that.
您能做的最好的事情是防止 B 类型的对象被实例化。在这种情况下,我建议您接受 kts 的建议并记录A(或其他任何东西)不打算用于继承的事实,给它一个非虚拟析构函数,并且没有其他虚拟函数,然后就这样了。
回答by KitsuneYMG
You are going through contortions to prevent further subclassing. Why? Document the fact that the class isn't extensible and make the dtor non-virtual. In the spirit of c, if someone really wants to ignore the way you intended this to be used why stop them? (I never saw the point of final
classes/methods in java either).
您正在通过扭曲来防止进一步的子类化。为什么?记录类不可扩展的事实并使 dtor 成为非虚拟的。本着 c 的精神,如果有人真的想忽略您打算使用它的方式,为什么要阻止他们?(我也从未final
在 Java 中看到类/方法的意义)。
//Note: this class is not designed to be extended. (Hence the non-virtual dtor)
struct DontExtened
{
DontExtened();
/*NOT VIRTUAL*/
~DontExtened();
...
};
回答by Whoever
1) is a matter of taste. If I see it correctly, your more fancy 2nd and 3rd solutions move the error in certain circumstances from link time to compile time, which in general should be better.
1)是口味问题。如果我没看错,你更花哨的第二个和第三个解决方案在某些情况下将错误从链接时移到编译时,这通常应该更好。
2) Virtual inheritance is needed to force the responsibility to initialize the (virtual) base class to the most derived class from where the base class ctor is no longer reachable.
2)需要虚拟继承来强制将(虚拟)基类初始化为基类ctor不再可达的最派生类的责任。
回答by Francis Boivin
To answer your question, you can't inherit from CBase because in virtual inheritance a derived class would need to have direct access to the class from which it was inherited virtually. In this case, a class that would derive from CBase would need to have direct access to CSealed which it can't since the constructor is private.
要回答您的问题,您不能从 CBase 继承,因为在虚拟继承中,派生类需要直接访问从其虚拟继承的类。在这种情况下,从 CBase 派生的类需要直接访问 CSealed,因为构造函数是私有的,所以它不能直接访问。
Though I don't see the usefulness of it all (ie: stopping inheritance) you can generalize using templates (I don't think it compiles on all compilers but it does with MSVC)
虽然我没有看到这一切的用处(即:停止继承),但您可以使用模板进行概括(我不认为它可以在所有编译器上编译,但可以在 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>
{
};
回答by T.E.D.
If you can, I'd go for the first option (private constructor). The reason is that pretty much any experienced C++ programmer will see that at a glance and be able to recognize that you are trying to prevent subclassing.
如果可以,我会选择第一个选项(私有构造函数)。原因是几乎所有有经验的 C++ 程序员都会一眼看出这一点,并且能够认识到您正在试图阻止子类化。
There might be other more tricky methods to prevent subclassing, but in this case the simpler the better.
可能还有其他更棘手的方法来防止子类化,但在这种情况下,越简单越好。
回答by Vijay
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
I found it here to give credit. I am posting here just other people can easily access http://www.devx.com/tips/Tip/38482
我在这里找到它来给予信任。我在这里发帖只是其他人可以轻松访问 http://www.devx.com/tips/Tip/38482
回答by B?a?ej Czapp
To elaborate on Francis' answer: if class Bottom
derives from class Middle
, which virtually inherits from class Top
, it is that most derived class (Bottom
) that is responsible for constructing the virtually inherited base class (Top
). Otherwise, in the multiple-inheritance/diamond-of-death scenario (where virtual inheritance is classically used), the compiler wouldn't know which of the two "middle" classes should construct the single base class. The Middle
's constructor's call to the Top
's constructor is therefore ignored when Middle
is being constructed from Bottom
:
详细说明Francis 的回答:如果 classBottom
派生自 class Middle
,而class虚拟继承自 class Top
,则大多数派生类 ( Bottom
) 负责构造虚拟继承的基类 ( Top
)。否则,在多重继承/死亡钻石场景中(虚拟继承被经典使用),编译器将不知道两个“中间”类中的哪一个应该构造单个基类。在Middle
类的构造函数对通话Top
时的构造函数'因此忽略Middle
正在从构成Bottom
:
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() {}
}
So, in the the approach 2) or 3) in your question, Bottom()
can't call Top()
because it's inherited privately (by default, like in your code, but it's worth making it explicit) in Middle
and thus is not visible in Bottom
. (source)
因此,在您的问题中的方法 2) 或 3) 中,Bottom()
无法调用,Top()
因为它是私下继承的(默认情况下,就像在您的代码中一样,但值得明确说明)Middle
,因此在Bottom
. (来源)