24

Scott 在《Effective C++, 3rd Edition, pg.》上说。43 要创建一个抽象类,我们只需要给它一个纯虚析构函数:

class AWOV {                  // AWOV = "Abstract w/o Virtuals"
public:
  virtual ~AWOV() = 0;        // declare pure virtual destructor
};

然后,他继续说有一个转折点:我们必须为纯虚析构函数提供一个定义:

AWOV::~AWOW() {}              // definition of pure virtual dtor

我的问题是,通过指定= 0,对于纯虚函数,我们说该函数不能对声明这个纯虚函数的类有任何定义。

为什么在这里为纯虚拟析构函数提供定义(即使它是空的)也可以?

4

6 回答 6

14

“我们是说函数不能对声明这个纯虚函数的类有任何定义。”

这不是纯虚拟的意思。纯虚拟只意味着包含的类不能被实例化(是抽象的),所以它必须被子类化,并且子类必须覆盖该方法。例如,

struct A {
    virtual ~A() = 0;
};

A::~A() {}

struct B : A {};

int main()
{
    A a;  // error
    B b;  // ok
}

这里,B析构函数是隐式定义的。如果它是另一种纯虚拟方法,则必须显式覆盖它:

struct A {
    virtual void foo() = 0;
};

void A::foo() {}

struct B : A {};

int main()
{
    B b;  // error
}

当基类必须是抽象的但仍提供一些默认行为时,需要为纯虚方法提供定义。

在析构函数的特定情况下,必须提供它,因为它会在子类实例被销毁时自动调用。尝试使用没有定义的纯虚析构函数实例化类的子类的程序将不会通过链接器。

于 2012-10-16T15:56:34.450 回答
7

使其成为纯粹的派生(非抽象)类来实现自己的。

提供实现允许派生类调用基类行为(默认情况下析构函数会这样做)。

于 2012-10-16T15:57:28.033 回答
5

有2例。

纯虚析构函数

这种情况是由标准专门处理的。

12.4 析构函数 [class.dtor]

9)析构函数可以声明virtual(10.3)或纯virtual(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。如果一个类有一个带有虚拟析构函数的基类,那么它的析构函数(无论是用户声明的还是隐式声明的)都是虚拟的。

析构函数的情况不同,因为所有析构函数在继承层次结构(假设正确删除)中以相反的构造顺序调用,即使不是显式的。因此,当对象被删除时会调用基类析构函数——这就是它需要实现的原因。

纯虚方法

它们与析构函数的不同之处在于它们不需要实现,也不需要实现。缺少要求的不同之处在于,当 aDerived::foo()被调用时,它不会自动调用Base::foo()(不是它可以,因为它可以实现或不可以实现)。

为什么要实现纯virtual方法取决于具体情况。我将纯说明符视为对程序员的提示,而不是与逻辑相关。它告诉你——程序员——你应该实现那个方法。基类是否有实现并不重要。

通过指定 = 0,对于纯虚函数,我们说该函数不能对声明此纯虚函数的类有任何定义。

并不真地。您是说派生的非抽象类必须覆盖该函数。这并不妨碍您自己实现它。

于 2012-10-16T16:11:26.627 回答
2

对于所有纯虚函数,这不是必需的。一点也不。

这样,派生类仍然会被强制覆盖实现,但基类中会有一个默认实现,不时之需。这就是这里的情况——因为你正在处理一个析构函数:当一个派生对象被销毁时,它的析构函数被调用,它的基类析构函数也被调用。这就是为什么您需要实现A::~A.

于 2012-10-16T15:59:27.723 回答
0

通过使函数成为纯虚函数,我们强制类的用户用派生类中的另一个函数替换该函数。

基类函数仍然可以调用BaseClass::myfunction(...)

现在,基类可能想要提供派生类可以使用的一些核心功能,如果它选择这样做的话。

于 2012-10-16T15:59:11.340 回答
-1

正确答案:假设类中有 2 个纯虚函数。现在假设两者都有实现。为 PVF 提供实现的原因是,如果通过实现这些 PVF 方法由子类派生基类,则基类方法可以充当默认行为(使类变得具体)

于 2021-12-08T14:17:43.903 回答