为什么必须提供纯虚析构函数的定义

本文介绍如何通过声明纯虚析构函数创建抽象类,即使该类没有其他纯虚函数。解释了为何在抽象类中需要虚析构函数,并展示了如何正确地定义和实现纯虚析构函数。

转载:http://blog.chinaunix.net/uid-25544300-id-3236826.html

部分修改,感谢博主!

在 某些类里声明纯虚析构函数很方便。纯虚函数将产生抽象类——不能实例化的类(即不能创建此类型的对象)。有些时候,你想使一个类成为抽象类,但刚好又没有 任何纯虚函数。怎么办?因为抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以方法很简单:在想要成为抽象类的类里声明 一个纯虚析构函数。

class awov
{
public:
  virtual ~awov() = 0; // 声明一个纯虚析构函数
};

 这个类有一个纯虚函数,所以它是抽象的,而且它有一个虚析构函数,所以不会产生析构函数问题。但这里还有一件事:必须提供纯虚析构函数的定义:

awov::~awov() {} // 纯虚析构函数的定义

  这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。这就是说,即使是抽象类,编译器也要产生对~awov()的调用,所以要保证为它提供函数体。如果不这么做,链接器就会检测出来,最后还是得回去把它添上。

虽然抽象类的析构函数可以是纯虚函数,但要实例化其派生类对象,仍必须提供抽象基类中析构函数的函数体。

转载于:https://www.cnblogs.com/Bejadin/p/3939472.html

<think>好的,我现在需要回答用户关于C++中虚析构函数的问题,特别是是否必须重写以及使用场景和原因。首先,我得回忆一下C++中虚析构函数虚析构函数的基本概念。 根据用户提供的引用,特别是引用[4]和引用[5],虚析构函数的作用是确保在多态情况下正确调用派生类的函数,避免资源泄漏。引用[4]提到,如果基类函数不是函数,通过基类指针删除派生类对象时,只会调用基类的函数,导致派生类的资源未释放。而虚析构函数可以强制派生类重写函数,但这里可能有个误区,因为虚析构函数在基类中仍需要提供实现,这一点需要特别注意。 接下来,用户的问题是虚析构函数是否必须被重写。根据C++的规则,当类中有函数时,该类成为抽象类,不能实例化。但函数比较特殊,即使声明为的,仍然需要在类外提供定义,否则链接时会报错。同时,派生类是否需要显式重写虚析构函数?实际上,如果基类的函数是的,但派生类可能不会显式重写它,因为函数的名字与类名相关,每个类的函数都是不同的。不过,根据C++标准,即使基类的函数是的,派生类在实例化时必须提供函数的实现,否则派生类也会成为抽象类,无法实例化。因此,用户可能需要明确这一点:派生类必须实现基类的虚析构函数,但这里的“实现”可能指的是基类的虚析构函数需要有定义,而派生类自身的函数会自动覆盖? 这里可能存在混淆,需要进一步查证。例如,基类声明虚析构函数后,必须在类外定义(即使函数体为空),否则派生类的函数无法正确链接。而派生类在定义自己的函数时,会自动调用基类的函数,因此不需要显式重写,但必须确保基类的虚析构函数有实现。因此,用户的问题的答案应该是:虚析构函数在基类中必须提供定义,而派生类不需要显式重写,但如果不重写,派生类仍然是抽象类吗?或者,由于函数的特殊性,即使基类函数是的,派生类如果没有自己的函数,是否仍然可以实例化?这点可能需要进一步确认。 根据C++标准,声明了虚析构函数的类成为抽象类,无法实例化。派生类必须重写所有函数才能成为具体类。但函数的情况特殊,因为即使基类函数是的,派生类的函数会自动生成,但可能不会覆盖基类的虚析构函数,导致派生类仍然是抽象类。因此,实际上,派生类必须显式提供函数的实现,即使只是默认的,才能覆盖基类的虚析构函数。但根据我的理解,可能不需要显式重写,因为函数的名字不同,但这里可能存在误区,需要进一步核实。 例如,引用[4]中提到,将函数声明为的另一个重要原因是确保正确的对象销毁顺序。但基类的虚析构函数必须定义,否则链接错误。例如: class Base { public: virtual ~Base() = 0; }; Base::~Base() {} // 必须定义 class Derived : public Base { public: ~Derived() override {} // 必须定义,否则Derived无法实例化 }; 在这种情况下,Derived的函数会被视为覆盖了基类的虚析构函数,因此Derived不再是抽象类。因此,即使基类函数是的,只要在基类中提供定义,派生类可以有自己的函数(即使不显式定义,编译器也会生成默认的),从而使得派生类可以实例化。然而,如果基类的虚析构函数没有定义,则链接时会报错,因为派生类的函数会隐式调用基类函数,而此时基类的函数未定义。 总结来说,虚析构函数在基类中必须提供定义,否则链接错误。而派生类是否需要显式重写函数?实际上,只要派生类实现了基类的所有函数(包括函数),就可以实例化。但由于函数是特殊的,即使基类声明为,只要在基类中定义,派生类即使不显式定义函数,编译器也会自动生成,从而覆盖基类的虚析构函数,使派生类成为具体类。但这里可能需要验证是否正确。 例如,假设基类Base有虚析构函数,并在类外定义。派生类Derived没有显式定义函数,那么Derived是否可以被实例化?根据C++规则,函数不会被继承,每个类都有自己的函数,因此Derived的函数会被隐式生成,并且会调用基类的函数。此时,Derived是否仍然需要显式重写基类的虚析构函数?答案是不需要,因为基类的虚析构函数已经被定义,而派生类的函数隐式生成了,因此Derived可以实例化。也就是说,基类声明虚析构函数后,只要基类提供定义,派生类无需显式重写函数即可实例化。但此时基类仍然是一个抽象类,无法实例化,而派生类不是抽象类,因为它的函数覆盖了基类的虚析构函数。 所以,回到用户的问题:虚析构函数是否必须被重写?答案是,在派生类中不需要显式重写,只要基类的虚析构函数定义,派生类的函数会自动生成并覆盖,从而允许派生类实例化。因此,虚析构函数的特殊之处在于,即使声明为,也必须提供定义,而派生类不需要显式重写,但必须确保基类的定义存在。 使用场景方面,当希望一个类成为抽象类(无法实例化),但该类没有其他合适的函数时,可以将函数声明为的,并同时提供定义。这在设计基类时常见,尤其是作为接口类时,强制派生类实现其他函数,同时确保正确的顺序。 关于原因,主要是为了在多态使用时正确调用派生类的函数,避免内存泄漏。同时,虚析构函数使得基类成为抽象类,防止直接实例化基类。 总结回答的结应该是: 1. 必须重写吗?不需要显式重写,但基类必须提供定义,派生类可以隐式生成函数。 2. 使用场景:基类作为接口,需要抽象类且无其他函数时。 3. 原因:确保正确,防止资源泄漏,强制基类为抽象类。 同时需要引用提供的资料,如引用[4]和引用[5]中的相关内容,说明虚析构函数的作用和必要性。</think>### 虚析构函数的特性与使用 #### 1. 是否必须重写? **不需要显式重写**,但需满足以下条件: - **基类必须提供虚析构函数定义**。虚析构函数虽被声明为`=0`,但必须单独定义实现(否则链接报错)[^4]。例如: ```cpp class Base { public: virtual ~Base() = 0; // 声明为 }; Base::~Base() {} // 必须定义 ``` - **派生类函数隐式覆盖**。派生类的函数会自动生成(若未显式定义),并隐式调用基类函数,因此派生类无需显式重写基类虚析构函数即可实例化[^4][^5]。 #### 2. 使用场景 1. **需要定义抽象类但无其他函数时** 若基类仅需作为接口且无其他适合设为的函数,可将函数设为以强制类为抽象类。 2. **确保多态对象正确销毁** 通过基类指针删除派生类对象时,若基类函数为函数(或但已定义),会正确调用派生类函数,避免资源泄漏[^5]。 #### 3. 原因分 1. **避免资源泄漏** 若基类函数非,通过基类指针删除派生类对象时,仅基类函数被调用,导致派生类资源未释放。 2. **强制抽象类特性** 虚析构函数使基类成为抽象类,阻止直接实例化基类对象,符合接口设计需求。 3. **特殊语法要求** 虚析构函数必须定义,因其调用链依赖顺序(派生类后自动调用基类)[^4]。 --- ### 示例代码 ```cpp // 基类声明虚析构函数 class AbstractBase { public: virtual ~AbstractBase() = 0; }; AbstractBase::~AbstractBase() {} // 必须定义 // 派生类隐式生成函数 class ConcreteDerived : public AbstractBase { public: // 无需显式定义函数 }; int main() { ConcreteDerived obj; // 合法:派生类可实例化 // AbstractBase base; // 错误:基类是抽象类 return 0; } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值