了解虚拟析构函数

Soh*_*amC 5 c++ gcc

我试图熟悉OOP概念,但不太明白它的概念virtual.

  1. 一个人可以创造一个virtual destructor而不是一个virtual constructor.为什么?
  2. virtual destructors内部如何处理?我指的是连接虚析构函数说明了这个概念,但我的问题是如何将vptr两者的vtableS(派生和基地)被称为?(在虚拟成员函数的情况下,当这种情况发生时vptr,Derived类指向的函数通常只被调用)
  3. 是否有其他情况可能需要使用virtual destructor

任何人都可以通过链接/示例帮助我理解上述概念吗?

bar*_*nos 8

首先,关于虚函数和非虚函数之间的区别:

您可以在编译或链接期间解析代码中的每个非虚函数调用.

通过解析,我们的意思是函数的地址可以由编译器或链接器计算.

因此,在创建的目标代码中,函数调用可以替换为操作码,以便跳转到内存中该函数的地址.

使用虚函数,您可以调用只能在运行时解析的函数.

我们不是解释它,而是通过一个简单的场景:

class Animal
{
    virtual void Eat(int amount) = 0;
};

class Lion : public Animal
{
    virtual void Eat(int amount) { ... }
};

class Tiger : public Animal
{
    virtual void Eat(int amount) { ... }
};

class Tigon : public Animal
{
    virtual void Eat(int amount) { ... }
};

class Liger : public Animal
{
    virtual void Eat(int amount) { ... }
};

void Safari(Animal* animals[], int numOfAnimals, int amount)
{
    for (int i=0; i<numOfAnimals; i++)
        animals[i]->Eat(amount);
    // A different function may execute at each iteration
}
Run Code Online (Sandbox Code Playgroud)

您可能已经理解,该Safari功能可以让您灵活地喂养不同的动物.

但由于每个动物的确切类型直到运行时才知道,因此Eat要调用的确切函数也是如此.


类的构造函数不能是虚拟的,因为:

调用对象的虚函数是通过对象类的V-Table执行的.

每个对象都包含一个指向其类的V-Table的指针,但只有在创建对象时才会在运行时初始化此指针.

换句话说,只有在调用构造函数时才会初始化此指针,因此构造函数本身不能是虚拟的.

除此之外,构造函数首先不是虚拟的.

虚函数背后的想法是,您可以在不知道调用它们的对象的确切类型的情况下调用它们.

当您创建对象时(即,当您隐式调用构造函数时),您确切地知道要创建的对象类型,因此您不需要此机制.


基类的析构函数必须是虚拟的,因为:

当您静态分配其类继承自基类的对象时,则在函数的末尾(如果对象是本地的)或程序(如果对象是全局的),将自动调用类的析构函数,并且反过来,调用基类的析构函数.

在这种情况下,析构函数是虚拟的这一事实没有意义.

另一方面,当您动态分配(new)一个类继承自基类的对象时,您需要delete在程序执行的稍后时刻动态解除分配()它.

delete操作者需要一个指针的对象,其中指针的类型可以是基类本身.

在这种情况下,如果析构函数是虚拟的,那么delete运算符将调用类的析构函数,而析构函数又调用基类的析构函数.

但是如果析构函数不是虚拟的,那么delete运算符将调用基类的析构函数,并且永远不会调用实际类的析构函数.

请考虑以下示例:

class A
{
    A() {...}
    ~A() {...}
};

class B: public A
{
    B() {...}
    ~B() {...}
};

void func()
{
    A* b = new B(); // must invoke the destructor of class 'B' at some later point
    ...
    delete b; // the destructor of class 'B' is never invoked
}
Run Code Online (Sandbox Code Playgroud)