通过定义默认私有构造函数使类不可继承

Posted

技术标签:

【中文标题】通过定义默认私有构造函数使类不可继承【英文标题】:Making a class non-inheritable by defining default private constructor 【发布时间】:2017-08-09 19:41:55 【问题描述】:

虽然我已经看到final 和虚拟继承方法实现了这一点,但我不明白为什么除了默认的私有构造函数之外不定义构造函数并不能阻止类被继承。 (此外,基类的复制构造函数和复制赋值方法应声明为私有,以防万一。)

基本上我的意思是,如果基类的构造函数是私有的并且没有其他构造函数,那么,当派生类想要扩展这个基类时:

    派生类不能调用基类的默认构造函数,因为它被定义为私有的

    派生类不能调用基类的任何非默认构造函数,因为没有这样的构造函数

所以这是一个编译时错误,我找不到其他方法来解决这个问题。

我确定我在某个地方错了;否则,我可以在 Internet 上找到一个页面,该页面提供了这种方法来使类不可继承,但请向我解释为什么我错了。

【问题讨论】:

你也可以使用你的方法。如果您深入挖掘,您可能会发现这两种方法有何不同,以及何时应该使用其中一种方法。 我不确定你在这里问什么。您是否想知道 如果 这行得通,或者 为什么 它行得通,或者如何解决它? @R Sahu 你能解释一下区别或提供我可以阅读搜索的链接相关关键字吗? @meagar 实际上,我什至没有尝试过我提到的方法,但我想知道这是否有效,如果有效,为什么不将其作为使文学类不可继承的一种方式? @mualloc 因为我们现在有final?是的,当然你可以为此使用私有构造函数,但你为什么要这样做呢?既然存在final,那就是错误 解决方案。你可以用扳手敲钉子,但你不应该想知道为什么“文献”在锤子存在时不提这个事实。 【参考方案1】:

final 和私有构造函数不是一回事。

考虑一下:

struct A final ;
struct B: A ;

int main() 

它不会编译,这是事实。 现在考虑一下:

class A  A()  ;
struct B: A ;

int main() 

它编译。好的,碰巧B() 构造函数被删除但你没有使用它。如果您将定义稍微更改为:

struct B: A  B(): A()  ;

无论如何,前面的例子只是 works(对于 works 的一些意思),那么有什么区别呢?final 禁止继承。私有构造函数不允许您构造 that 类型的对象,但您仍然可以定义 that 类型。因此你可以做这样的事情(这没有多大意义,但会给你一个想法):

#include<type_traits>

class A  A() ;
struct B: A ;

template<typename T>
void f() 
    static_assert(std::is_base_of<A, B>::value, "!");
    // ...


int main() 
    f<B>();

如果不能从A 继承,它如何编译?因为您的假设是错误的,您可以从A 继承。您不能构造B 类型的对象,但您仍然可以使用B 作为类型,只要您不尝试创建实例。另一方面,如果你把final放在那里,你会得到一个编译时错误,仅此而已,你不能以任何方式使用B类型。

【讨论】:

class A 的构造函数是公开的,所以不是我说的。 @mualloc 类的默认可见性是private,因此class C C() ; 等价于class C private: C() ;。构造函数实际上并不公开。如果您尝试在第二个示例中构造 B,它将无法编译。 好的,您对默认可见性问题的看法是正确的,感谢您的解释。这就是我一直在寻找的。​​span> 顺便说一句,我很抱歉这么粗心,因为我没有编译我描述的代码,以便更好地发现和定义问题。 其实struct B: A 和struct B: A B(): A() 有什么区别?【参考方案2】:

为什么标准会禁止这样做?从理论上讲,没有什么能阻止您将 Derived 类声明为 Base 类的朋友。这将确保扩展基类的唯一可能方法是通过非常知名的类。我想不出任何实际的案例,我认为这很糟糕,但做这样的恐怖是可能的......

struct BaseClass

friend struct DerivedClass;

private:
    BaseClass() 
;

struct DerivedClass : BaseClass

public:
    DerivedClass() 
;

【讨论】:

以上是关于通过定义默认私有构造函数使类不可继承的主要内容,如果未能解决你的问题,请参考以下文章

Typescript构造函数和继承

不可变类/对象、私有构造函数、工厂方法

继承中的构造析构函数调用顺序

在继承的情况下编译器创建默认构造函数和用户创建默认构造函数之间的区别

在 C++ 中禁止复制构造函数的最可靠方法是啥?

C# 继承和默认构造函数