13

in基pure virtual destructor类应该有一个定义。否则编译器将在链接时从派生类析构函数生成对基类析构函数的调用,并导致链接错误。

我试图在基类中定义纯虚拟析构函数,如下所示:

class base
{
   public:
      base()
      {
         cout << "constructor in base class\n";
      }

      virtual ~base()=0
      {}
};

这给出了编译错误:

错误:函数定义上的纯说明符

然后我尝试在基类之外定义函数,如下所示:

class base
{
   public:
      base()
      {
         cout << "constructor in base class\n";
      }

      virtual ~base()=0;
};

base::~base()
{

}

这消除了编译错误,它的行为符合我的理解。

但我的问题是在基类之外定义纯虚析构函数如何消除编译错误?

4

5 回答 5

11

你的第二个例子是正确的。

许多其他答案都假设拥有具有默认实现的纯虚函数是非法的,但这是不正确的。

在纯虚拟析构函数的情况下,您必须有一个定义(请参阅 xmoex 答案中的链接)。

确实:

§10.4/2 函数声明不能​​同时提供纯说明符和定义

但是,正如您所注意到的,可以在声明之外提供定义。

于 2011-11-19T14:21:22.077 回答
7

我看了这个页面:

http://www.gotw.ca/gotw/031.htm

根据我的理解,纯虚拟析构函数必须有一个定义(甚至是空的),因为每个派生类都必须调用基类析构函数

于 2011-11-19T14:20:52.490 回答
5

写成无效的语法:

virtual ~base()=0
{}

如果你想提供一个纯虚成员函数的实现,你应该在类之外做。大多数时候你不应该这样做,因为无论如何都不应该调用纯虚函数。然而,可以为纯虚函数定义实现。

事实上,纯虚析构函数必须有一个实现。这是因为无论给定类中的析构函数是否为纯虚函数,都会在对象销毁时调用所有基类的析构函数。

因此,如果您创建任何派生类的实例,base那么在某些时候该对象所属的所有类的析构函数都将被调用,包括base::~base()析构函数。如果您不定义它,链接器将找不到所需的符号并会报错。

于 2011-11-19T14:20:02.317 回答
3

析构函数是唯一的方法,即使它是纯虚拟的,也必须有一个实现才能使定义它的类有用。因此,与@Kiril 的回答相反,我想说纯虚函数可以有实现。

有点离题:

struct base {
    virtual void func() = 0;
};

void base::func() { /* default implementation */ }

class derived : public base{
    void func() { base::func(); } // have to explicitly call default implementation.
};
于 2011-11-19T14:22:05.017 回答
1

纯虚方法可以有实现,但它们使基类抽象并强制派生类覆盖这些方法。

假设您在基类中有一个指针成员。你想在析构函数上删除它,但也要使类抽象——所以你实现纯虚拟析构函数。

这是一个实现细节——析构函数被实现的事实不应该从外部可见。

于 2011-11-19T14:20:29.683 回答