C++ 理解虚拟析构函数
我试图熟悉OOP的概念,但不太理解C++ 理解虚拟析构函数,c++,gcc,C++,Gcc,我试图熟悉OOP的概念,但不太理解virtual的概念 可以创建虚拟析构函数,但不能创建虚拟构造函数。为什么? 如何在内部处理虚拟析构函数?我的意思是链接说明了这个概念,但我的问题是如何调用vtables(派生和基本)的vptr?(对于虚拟成员函数,当这种情况发生时,通常只调用派生类的vptr指向的函数) 是否有其他可能需要使用虚拟析构函数的场景 有人能通过链接/示例帮助我理解上述概念吗?我假设我们有一个基类a,它是派生的B 1.:您可以通过A指针删除B,然后正确的方法是调用B析构函数。 然而,
virtual
的概念
虚拟析构函数
,但不能创建虚拟构造函数
。为什么?虚拟析构函数
?我的意思是链接说明了这个概念,但我的问题是如何调用vtable
s(派生和基本)的vptr
?(对于虚拟成员函数,当这种情况发生时,通常只调用派生类的vptr
指向的函数)虚拟析构函数的场景
有人能通过链接/示例帮助我理解上述概念吗?我假设我们有一个基类a,它是派生的B 1.:您可以通过A指针删除B,然后正确的方法是调用B析构函数。 然而,您不能说,当您实际上只是调用a构造函数时,应该创建一个B对象。根本没有这种情况。 你可以说:
A* a = new B ();
或
但两者都直接调用B的构造函数
2.:嗯,我不完全确定,但我猜它将遍历类层次结构的相关部分,并搜索最接近的函数调用。如果函数不是虚拟函数,它将停止迭代并调用它
3.:如果要从该类继承某些内容,则应始终使用虚拟析构函数。如果是最后一节课,你不应该
可以创建虚拟析构函数,但不能创建虚拟构造函数。为什么?
虚拟函数根据调用它们的对象的类型进行调度。调用构造函数时,没有对象——创建一个对象是构造函数的工作。没有对象,就不可能进行虚拟分派,因此构造函数不能是虚拟的
如何在内部处理虚拟析构函数
虚拟调度的内部细节由实现定义;该语言没有指定实现,只指定行为。通常,析构函数是通过vtable调用的,就像任何虚拟函数一样
如何调用vtable(派生和基本)的vptr
只有最派生的析构函数才会被虚拟调用。所有析构函数,无论是否为虚拟的,都将隐式调用所有成员和直接基类子对象的析构函数。(虚拟继承的情况稍微复杂一些;但这超出了这个问题的范围)
有没有其他可能需要使用虚拟析构函数的场景
为了支持多态删除,您需要一个;也就是说,能够通过指向基类型的指针删除派生类型的对象。如果基类型没有虚拟析构函数,这是不允许的,并且会给出未定义的行为
首先,谈谈虚拟函数和非虚拟函数之间的区别: 代码中的每个非虚拟函数调用都可以在编译或链接期间解析 通过解析,我们的意思是可以由编译器或链接器计算函数的地址 因此,在创建的目标代码中,函数调用可以替换为跳转到内存中该函数地址的操作代码 使用虚拟函数,您可以调用只能在运行时解析的函数 与其解释它,不如让我们运行一个简单的场景:
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
}
可以创建虚拟析构函数,但不能创建虚拟构造函数。
为什么?
我会试着用外行的话来解释这件事。
C++中的类只在构造函数完成后才存在。每个基类在派生类及其成员(包括vtable链接)初始化之前都存在。因此,拥有虚拟构造函数是没有意义的(因为要构造,您需要知道类型)。此外(在c++中),从构造函数调用虚函数不起作用(因为派生类的vtable部分尚未设置)。如果仔细考虑一下,允许从构造函数调用虚拟函数会打开一个蠕虫程序罐(例如,如果在成员初始化之前调用派生类的虚拟函数会怎么样)
就析构函数而言,在销毁点上,vtable是“完整的”,我们(c++运行时)完全知道该类型(可以这么说)。找到类型的最派生部分的析构函数(如果是虚拟的,则通过vtable),因此可以调用该析构函数,当然也可以调用所有基的析构函数
如何在内部处理虚拟析构函数?我指的是链接
虚拟析构函数说明了这个概念,但我的问题是
VTable(派生和基本)的vptr都被调用
析构函数的处理方式与普通虚拟函数相同(也就是说,如果地址是虚拟的,则会在vtable中查找地址,但代价是额外的一级(可能是2?)间接寻址)。此外,C++的保证
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
}
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
}