析构函数中的virtual是否必要?

我们经常听到建议要把构造函数不能为虚,析构函数最好为虚,这是为什么?

如下例子:

// pvtable1.cpp : 定义控制台应用程序的入口点。


#include "stdafx.h"

#include <iostream>

using namespace std;

class Base1 {

public:

    Base1(){ cout << "Base1::Base1()" << endl; }
    ~Base1(){ cout << "Base1::~Base1()" << endl; }

    virtual void f() { cout << "Base1::f" << endl; }

    virtual void g() { cout << "Base1::g" << endl; }

    virtual void h() { cout << "Base1::h" << endl; }

};

class Base2 {

public:
    Base2(){ cout << "Base2::Base2()" << endl; }
    ~Base2(){ cout << "Base2::~Base2()" << endl; }

    virtual void f() { cout << "Base2::f" << endl; }

    virtual void g() { cout << "Base2::g" << endl; }

    virtual void h() { cout << "Base2::h" << endl; }

};

class Base3 {

public:
    Base3(){ cout << "Base3::Base3()" << endl; }
    ~Base3(){ cout << "Base3::~Base3()" << endl; }

    virtual void f() { cout << "Base3::f" << endl; }

    virtual void g() { cout << "Base3::g" << endl; }

    virtual void h() { cout << "Base3::h" << endl; }

};

class Derive : public Base1, public Base2, public Base3 {

public:
    Derive(){ cout << "Derive::Derive()" << endl; }
    ~Derive(){ cout << "Derive::~Derive()" << endl; }

    virtual void f() { cout << "Derive::f" << endl; }

    virtual void g1() { cout << "Derive::g1" << endl; }

};
int doIt2()
{

    Base1 *pBase1 = new Derive();

    delete pBase1;

    return 0;

}

int _tmain(int argc, _TCHAR* argv[])
{
    doIt2();
    return 0;
}

当使用一个多重继承的时候,使用父类的指针删除子类的时候,发现了不能正常析构的情况,执行结果如下:

如果在将父类的析构函数定义为虚函数,便正常了

一个类中将所有的成员函数都尽可能地设置为虚函数总是有益的。虽然会增大开销

下面是设置虚函数的注意事项:

1、只有类的成员函数才能声明为虚函数。

2、静态成员函数不能使虚函数,因为它不受限于某个对象。

3、内联函数不能使虚函数。

4、构造函数不能是虚函数。

不用virtual 的几种情况:
1、作为非公有基类。仅作为 private base class 使用的 class 不需要使用虚拟析构函数
2、不作为接口使用的基类。
3. 如果你可以保证这个类不被public继承(private/protected继承的话,在非friend函数/类中就无法用基类指针指向派生类了)
4. 如果它的所有派生类(包括派生类的派生类)的析构函数都是trivial的(这里的trivial指的是在程序员的层次什么事也不做)
5. 如果不需要用基类的指针指向派生类的对象
在这五种情况下,不把析构函数声明为virtual都是可以的,何况效率会高一些——但前提是你得保证前提的成立——不过这些保证常常是很难100%的:谁能保证别人在派生你的类的时候,析构函数是trivial的,或者别人不用你提供的基类的指针指向派生类对象?这些常常是很难得到保证的。

时间: 2025-01-15 05:35:41

析构函数中的virtual是否必要?的相关文章

Effective C++ Item 09-绝不在构造函数和析构函数中调用virtual函数

Item 09-绝不在构造函数和析构函数中调用virtual函数(Never call virtual functions during construction or destruction) Why? 由于base class构造函数的执行更早于derived class构造函数,当base class构造函数执行derived class的成员变量尚未初始化.如果期间调用的virtual函数下降至derived class阶层,要知道derived class的函数几乎必然取用local成

绝不在构造和析构函数中调用 virtual 函数

看下面的这段代码,问 print调用的是基类还是派生类的版本? 答案是 基类... 可能大家会很惊讶,print不是virtual function 吗?为什么不是调用派生类的版本呢? 首先,当定义一个派生类的对象的时候, 由于 base class 构造函数的执行更早于 derived class构造函数, 所以当 base class constructor 调用的时候,派生类的成员尚未初始化(说明,这个时候真正的 虚函数表尚未完全初始化). 如果这个时候调用 派生类的函数(可能使用未初始化

第八章:不要在构造和析构函数中使用虚函数

前言 本文将讲解一个新手C++程序员经常会犯的错误 - 在构造/析构函数中使用虚函数,并分析错误原因所在以及规避方法. 错误起因 首先,假设我们以一个实现交易的类为父类,然后一个实现买的类,一个实现卖的类为其子类. 这三个类的对象初始化过程中,都需要完成注册的这么一件事情 (函数).然而,各自注册的具体行为是不同的. 有些人会写出以下这样的代码: 1 class Transaction { 2 public: 3 Transaction(); // 父类构造函数 4 //...... 5 pri

EC笔记,第二部分:9.不在构造、析构函数中调用虚函数

9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #include <iostream> using namespace std; class cls1{ public: cls1(){ newMake(); }; ~cls1(){ deleteIt(); }; virtual void newMake(){ cout<<"cls1 make"<<endl; } virtual void deleteIt()

不要在构造和析构函数中使用虚函数

前言 本文将讲解一个新手 C++ 程序员经常会犯的错误 - 在构造/析构函数中使用虚函数,并分析错误原因所在以及规避方法. 错误起因 首先,假设我们以一个实现交易的类为父类,然后一个实现买的类,一个实现卖的类为其子类. 这三个类的对象初始化过程中,都需要完成注册的这么一件事情 (函数).然而,各自注册的具体行为是不同的. 有些人会写出以下这样的代码: 1 class Transaction { 2 public: 3 Transaction(); // 父类构造函数 4 //...... 5 p

Effective C++ 条款九、十 绝不在构造和析构过程中调用virtual函数|令operator=返回一个reference to *this

  1.当在一个子类当中调用构造函数,其父类构造函数肯定先被调用.如果此时父类构造函数中有一个virtual函数,子类当中也有,肯定执行父类当中的virtual函数,而此时子类当中的成员变量并未被初始化,所以无法调用子类与之对应的函数.即为指向虚函数表的指针vptr没被初始化又怎么去调用派生类的virtual函数呢?析构函数也相同,派生类先于基类被析构,又如何去找派生类相应的虚函数? 2.做法:将子类的某个函数改为non-virtual,然后在子类构造函数中传递参数给父类函数.然后父类的构造函数

避免在析构函数中编写代码

上篇文章中,我们介绍了为什么应该彻底避免编写拷贝构造函数和赋值操作符.今天这篇我们讨论下为什么应该避免在析构函数中编写代码.即让析构函数为空. 例如: virtual ~MyClass() { } 我们用空析构函数这个术语表示花括号内没有代码的析构函数. 需要编写析构函数可能有如下几个原因: 在基类中,可能需要声明虚拟析构函数,这样就可以使用一个指向基类的指针指向一个派生类的实例. 在派生类中,并不需要把析构函数声明为虚拟函数,但是为了增强可读性,也可以这样做. 可能需要声明析构函数并不抛出任何

Effective C++ Item 9 绝不在构造和析构过程中调用virtual函数

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层) 示例: <pre name="code" class="cpp">#include <iostream> #include <string> using namespace std; c

NO.8:绝不在构造或者析构过程中调用virtual函数

在构造和析构执行期间不要调用virtual函数,因为这类调用从不会下降至derived class(比起当前执行构造函数和析构函数) 如果在base class 构造函数或者析构函数调用virtual,derived class构造时会先构造base class,则base class中的virtual实际调用是base class的; 第一种解释:derived class类先执行构造base class部分,然而在base class构造过程中,derived class部分是为初始化的,如