为什么基类的析构函数不是虚函数时,就不会调用派生类的析构函数
我知道,基类的析构函数要生命为虚函数,不然用基类指针删除派生类对象时只会调用基类的析构函数,而不会调用派生类的析构函数,从而发生内存泄露。但是为什么会这样?为什么基类析构函数不是虚函数时,就不会调用派生类析构函数而是虚函数时就会调用派生类析构函数???有没有大神指点一下。
看了几位的回答,都不是我想要的。我已经知道了不声明为虚函数,会造成内存泄露。我想知道为什么会造成内存泄露,原因是什么。
- 1. 析构函数跟普通成员没有什么不同,只是编译器在会在特定的时候自动调用析构函数(离开作用域或者执行delete操作);
- 2. 对于一个成员函数调用(不论是通过对象obj.func还是通过对象指针obj->func),到底是直接调用还是通过虚函数表调用,在编译的时候是确定的,取决于这个函数是不是虚函数;
- 3. 综上,如果析构不声明为虚函数,那么delete pBase,就被编译器解释为 Base::~Base,否则被编译器解释为 this->virtual_function_table[#析构在虚函数表的偏移]
因为虚函数就是做这个的啊。有虚函数的目的,就是为了可以在各级继承之间调用一个合适的方法,而不是直接调用名义上的那个方法。
多态是虚函数来实现的,没有虚函数,基类指针没法找到子类对应的虚函数地址,就没有办法调用,实现多态
非虚函数的地址是编译时决定的,其函数调用是直接调用, call $function;
虚函数的地址是运行时决定的,需要查虚函数表,是间接调用 call *%eax
// cat a.cc
struct A {
void f1(void);
void f2(void);
virtual void f3(void);
virtual void f4(void);
};
void f(struct A *pa)
{
pa->f1();
pa->f2();
pa->f3();
pa->f4();
}
gcc -S a.cc -o -
# %eax = this
...
call _ZN1A2f1Ev #call f1
...
call _ZN1A2f2Ev #call f2...
movl (%eax), %eax # virtual table
movl (%eax), %eax # entry #1
call *%eax # f3
...
movl (%eax), %eax # virtual table
addl $4, %eax # entry #2
movl (%eax), %eax # f4
call *%eax
父类引用指向子类对象,父类构造方法优先于子类,如使用了virtual,父类析构后,还会访问子类未初始化或析构的方法,这样造成程序指向混乱,最终崩溃,在语言设计之初,就规定不能使用这种方式了。
虚函数就是多态的机制,声明为虚函数主要是有一个虚函数表,虚函数表中存储了一些相关的地址,从而知道调用对应的函数。