在C++中,一个抽象类可以在没有纯虚拟函数的情况下实现吗

Can an abstract class be implemented without pure virtual functions in C++?

本文关键字:虚拟 函数 实现 情况下 C++ 一个 抽象类      更新时间:2023-10-16

我曾想过使用受保护的构造函数,但它不能完全解决这个问题,因为从中继承的类可以实例化基类。

至于私有构造函数,派生类也不会被实例化。

因此,任何合适的技术都将不胜感激。

不清楚您真正想要的是什么。所以让我试着澄清一些问题:

纯虚拟函数可以有定义

如果您关心的是要为基础中的所有虚拟函数提供定义,那么您可以为纯虚拟函数提供这些定义,并且它们将可用于静态调度。

Protected授予对基本子对象的访问权限,而不是对base的每个实例的访问权限

有一种常见的误解,认为protected允许特定的派生类型访问base的任何实例。这不是真的。关键字protected授予对派生类型内的base子对象的访问权限。

class base {
protected: base() {}
};
class derived : public base {
   derived() : base() {         // fine our subobject
      base b;                   // error, `b` is not your subobject
   }
};

抽象类的定义是至少有一个纯虚拟函数(virtual function-signature = 0;没有它们就无法创建抽象类。

在C++中,抽象类可以在没有纯虚拟函数的情况下实现吗?

如果您从静态多态性中选择观点,您可以做到这一点!

抽象基类将只是缺少派生类中接口方法的默认方法实现。

此外,您可以为那些CRTP基类模板使用受保护的构造函数,以要求实例化的继承。

更新:
我发现了一个很好的幻灯片,它全面地解释了静态多态性和动态多态性。每种技术都有其优缺点和特定的使用领域,此外,你可以将这两种技术混合使用(当然是明智的)。

为了详细说明,我将给出一个示例:

template<class Derived>
class AbstractBase
{
public:
    // Equivalent for a pure virtual function
    void foo()
    {
        // static_cast<> enforces an 'Is a' relation from Derived to AbstractBase
        static_cast<Derived*>(this)->fooImpl();
    }
    // Equivalent for simple virtual function (overidable from Derived)
    void bar()
    {
        static_cast<Derived*>(this)->barImpl();
    }
    // Default implementation for any call to bar()
    void barImpl()
    {
    }
protected:
    AbstractBase() {}
};

// Compilation will fail, since ConcreteClass1 doesn't provide 
// a declaration for fooImpl()
class ConcreteClass1
: public AbstractBase<ConcreteClass1>
{
}

// Compiles fine
class ConcreteClass2
: public AbstractBase<ConcreteClass2>
{
public:
    void fooImpl()
    {
        // Concrete implementation ...
    }
}

下面的示例显示了上面介绍的模式在抽象类和继承类(模板参数)之间强制执行"Is a"关系

class ConcreteClass3
{
public:
    void fooImpl()
    {
        // Concrete implementation ...
    }
}   
// Instantiation will fail, because 
// * the constructor is protected
// * at least the static cast will fail
AbstractBase<ConcreteClass3> instance; 

我在书中读过抽象类是专门用作基类的类。抽象类至少包含一个纯虚拟函数。通过在类声明中的虚拟成员函数声明中使用纯说明符(=0)来声明纯虚拟函数。