C++ 防止类被实例化

C++ 防止类被实例化,c++,abstract,C++,Abstract,最近有人问我以下问题: 您正在编写一个基类,希望其他人能够从中派生出供个人使用的基类。您希望没有人能够实例化您正在编写的基类(仅派生类的对象)。 您将如何实现该类 我想到了两种解决办法: 一种是使基类抽象(通过添加纯虚函数) 其次,将构造函数放在protected节下,这样外部的任何人都不能创建它的实例,只能创建派生类 我的问题是,我的解决方案(在你能想到的所有方面)之间有什么区别 谢谢。受保护的构造函数是合理的,但不会阻止类被实例化: class Foo { protected: Fo

最近有人问我以下问题:

您正在编写一个基类,希望其他人能够从中派生出供个人使用的基类。您希望没有人能够实例化您正在编写的基类(仅派生类的对象)。 您将如何实现该类

我想到了两种解决办法:

一种是使基类抽象(通过添加纯虚函数)

其次,将构造函数放在protected节下,这样外部的任何人都不能创建它的实例,只能创建派生类

我的问题是,我的解决方案(在你能想到的所有方面)之间有什么区别


谢谢。

受保护的构造函数是合理的,但不会阻止类被实例化:

class Foo
{
protected:
    Foo() = default;
public:
    static Foo make() { return Foo(); }
};

int main()
{
    auto f = Foo::make(); 
}
另一方面,抽象类永远不能被实例化,这正是您在这里想要的


然而,重要的问题是,您是否真的需要一个多态层次结构,在这个层次结构中,您需要在运行时决定类型,并通过基指针处理异构对象集合。如果是这样的话,那么一个抽象的基础就是要走的路。如果不是,则不能拥有没有虚拟函数的抽象类,而受保护的构造函数(和析构函数)是表示需要不可实例化的基的唯一方法。

受保护的构造函数是合理的,但不会阻止类被实例化:

class Foo
{
protected:
    Foo() = default;
public:
    static Foo make() { return Foo(); }
};

int main()
{
    auto f = Foo::make(); 
}
另一方面,抽象类永远不能被实例化,这正是您在这里想要的


然而,重要的问题是,您是否真的需要一个多态层次结构,在这个层次结构中,您需要在运行时决定类型,并通过基指针处理异构对象集合。如果是这样的话,那么一个抽象的基础就是要走的路。否则,没有虚拟函数就不能有抽象类,而受保护的构造函数(和析构函数)是表示需要不可实例化的基类的唯一方法。

纯虚拟函数会将虚拟函数表的开销添加到基类中,如果需要使对象非常小,这可能是一个问题。通过使用受保护的构造函数和/或受保护的析构函数,可以避免这种开销。受保护的析构函数有助于防止通过基类指针意外删除,在没有虚拟析构函数的情况下,基类指针会导致未定义的行为。

纯虚拟函数会将虚拟函数表的开销添加到基类中,如果需要将对象保持得非常小,这可能是一个问题。通过使用受保护的构造函数和/或受保护的析构函数,可以避免这种开销。受保护的析构函数有助于防止通过基类指针意外删除,在没有虚拟析构函数的情况下,基类指针会导致未定义的行为。

我认为受保护的构造函数足以阻止该类被实例化。通过添加一个静态成员函数来返回实例,您有点“作弊”。即使是作弊,一个
受保护的
私有的
复制构造函数也会阻止你。@Nikbugalis:我也可以有一个静态函数返回一个
新的Foo
——不需要复制:-Sright-但关键是如果你要作弊,游戏就结束了。但您确实强调了私有构造函数是如何不够的,以及它与在基类中使用纯虚函数来阻止实例化的区别。我认为
受保护的
构造函数足以阻止此类被实例化。通过添加一个静态成员函数来返回实例,您有点“作弊”。即使是作弊,一个
受保护的
私有的
复制构造函数也会阻止你。@Nikbugalis:我也可以有一个静态函数返回一个
新的Foo
——不需要复制:-Sright-但关键是如果你要作弊,游戏就结束了。但是您强调了私有构造函数是如何不够的,以及它与在基类中使用纯虚拟函数以防止实例化有何区别。