我试图使自己熟悉OOP概念,但不能完全理解OOP的概念virtual
。
virtual destructor
但不能创建一个virtual constructor
。为什么?virtual destructors
内部如何处理?我的意思是虚拟析构函数链接说明了这一概念,但我的问题是如何vptr
同时vtable
调用s(派生基数和基数)的?(在虚拟成员函数的情况下,通常发生这种情况时vptr
,将仅调用派生类所指向的函数)virtual destructor
吗?任何人都可以通过链接/示例来帮助我理解以上概念吗?
首先,介绍一下虚拟功能和非虚拟功能之间的区别:
在编译或链接期间,可以解析代码中的每个非虚拟函数调用。
通过resolve,我们的意思是函数的地址可以由编译器或链接器计算。
因此,在创建的目标代码中,可以使用操作码替换函数调用,以跳转到内存中该函数的地址。
使用虚函数,您可以调用只能在运行时解析的函数。
我们不做解释,而是通过一个简单的场景进行说明:
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
}
如您可能理解的那样,该Safari
功能使您可以灵活地饲养不同的动物。
但是,由于直到运行时才知道每种动物的确切类型,因此Eat
要调用的确切函数也是如此。
类的构造函数不能是虚拟的,因为:
通过对象类的V表执行对象的虚函数的调用。
每个对象都拥有一个指向其类的V表的指针,但是该指针仅在创建对象时在运行时初始化。
换句话说,仅在调用构造函数时才初始化此指针,因此构造函数本身不能是虚拟的。
除此之外,构造函数首先是虚拟的是没有意义的。
虚拟函数背后的想法是,您可以在不知道调用它们的对象的确切类型的情况下调用它们。
在创建对象时(即,当您隐式调用构造函数时),您确切地知道要创建的对象类型,因此不需要此机制。
基类的析构函数必须是虚拟的,因为:
当静态分配其类从基类继承的对象时,则在函数(如果该对象是本地的)或程序(如果该对象是全局的)的末尾,将自动调用该类的析构函数,并且依次调用基类的析构函数。
在这种情况下,析构函数是虚拟的这一事实没有任何意义。
另一方面,当您动态分配(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
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句