C ++纯虚拟类是否需要定义?

时间:2017-04-20 12:41:31

标签: c++ class

考虑:

// in header.h
class A {
public:
    virtual ~A() = 0;
};


class B : public A {
public:
    ~B() override {}
}

链接器报告无法解析:

  

外部符号“public:virtual __thiscall A ::〜A(void)”在函数“public:virtual __thiscall B :: ~B(void)”中引用

我发现我必须写出A::~A()的定义。

我曾经认为纯虚拟类定义了接口(函数声明),并且它们不必包含函数定义。我应该为纯虚基类中的所有虚函数编写定义吗?或者我应该只需要编写析构函数?

4 个答案:

答案 0 :(得分:17)

这是因为与常规虚函数不同,析构函数不仅仅是重写。当您在基类上调用常规虚函数时,最终调用已覆盖该函数的函数。

但是,对于析构函数,还必须调用基类的析构函数。但由于您未提供~A()的实现,因此您的代码无法链接。

但即使它是纯虚拟的,你也可以定义它:like here

答案 1 :(得分:10)

  

C ++ 纯虚拟类是否需要定义?

第一个错误是您代表自己发明了条款。没有“纯粹的虚拟课”这样的东西。只有“虚拟功能”和“纯虚功能”。理解没有这样的东西“纯虚拟类”是理解为什么这个问题不成立的关键。

  

我曾经认为纯虚拟类定义了一个接口(函数声明)

我认为C ++不是你的第一语言,而是继Java / C#之后的第二语言,你认为Java / C#的想法与C ++无关。

C ++有接口 - 它只是类的声明:

struct A{

    void doNothing();

};

//A.cpp:
void A::doNothing(){

}

这是struct A的接口。它与继承,虚函数还是多态有什么关系?不,它只是类的声明,其中存在哪些方法和属性。

每个类都需要一个有效的析构函数来允许程序清理对象资源 - 内存等。它与多态无关。在您的示例中,A需要以某种方式被破坏。 B继承它并不重要。当它超出范围时,它必须告诉程序如何处理它。

如评论中所述,如果您只想要一个虚拟析构函数(因此在A* a = new B()的情况下不会显示UB),只需将析构函数声明为默认值:

virtual ~A() = default;

答案 2 :(得分:4)

作为对我的前任的补充,你可以阅读它here

  

可以提供纯虚函数的定义(,如果纯虚拟是析构函数,则必须提供):派生类的成员函数可以自由调用抽象基数&#39 ; s纯虚函数使用限定函数id。这个定义必须在类体之外提供(函数声明的语法不允许纯说明符= 0和函数体)

答案 3 :(得分:2)

要创建一个类摘要,您需要使至少一个虚函数变纯。如果你没有任何其他的,那么析构函数可能是一个很好的候选者。但另一方面,破坏者是一种特殊情况 - 即使它是纯粹的,你也必须定义它。

注意:您也可以定义常规纯虚函数,例如拦截错误条件(类似纯函数从ctor或dtor调用),但与析构函数不同,不提供这样的定义并且编译器会在那里生成错误处理程序,它将报告名为。

的纯虚函数