2 l108103t l108103t 于 2015.06.05 15:35 提问

为什么基类的析构函数不是虚函数时,就不会调用派生类的析构函数

我知道,基类的析构函数要生命为虚函数,不然用基类指针删除派生类对象时只会调用基类的析构函数,而不会调用派生类的析构函数,从而发生内存泄露。但是为什么会这样?为什么基类析构函数不是虚函数时,就不会调用派生类析构函数而是虚函数时就会调用派生类析构函数???有没有大神指点一下。

看了几位的回答,都不是我想要的。我已经知道了不声明为虚函数,会造成内存泄露。我想知道为什么会造成内存泄露,原因是什么。

7个回答

nswcfd
nswcfd   2015.06.05 19:41
已采纳
  1. 1. 析构函数跟普通成员没有什么不同,只是编译器在会在特定的时候自动调用析构函数(离开作用域或者执行delete操作);
  2. 2. 对于一个成员函数调用(不论是通过对象obj.func还是通过对象指针obj->func),到底是直接调用还是通过虚函数表调用,在编译的时候是确定的,取决于这个函数是不是虚函数;
  3. 3. 综上,如果析构不声明为虚函数,那么delete pBase,就被编译器解释为 Base::~Base,否则被编译器解释为 this->virtual_function_table[#析构在虚函数表的偏移]
gamefinity
gamefinity   Rxr 2015.06.05 15:41

因为虚函数就是做这个的啊。有虚函数的目的,就是为了可以在各级继承之间调用一个合适的方法,而不是直接调用名义上的那个方法。

l108103t
l108103t 你这个解释。。。说了等于没说
2 年多之前 回复
caozhy
caozhy   Ds   Rxr 2015.06.05 16:27
CodeofWorker
CodeofWorker   2015.06.05 16:36

父类引用指向子类对象,父类构造方法优先于子类,如使用了virtual,父类析构后,还会访问子类未初始化或析构的方法,这样造成程序指向混乱,最终崩溃,在语言设计之初,就规定不能使用这种方式了。

zhangsong0709
zhangsong0709   2015.06.05 16:37

虚函数就是多态的机制,声明为虚函数主要是有一个虚函数表,虚函数表中存储了一些相关的地址,从而知道调用对应的函数。

nswcfd
nswcfd   2015.06.05 20:09

非虚函数的地址是编译时决定的,其函数调用是直接调用, 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

oyljerry
oyljerry   Ds   Rxr 2015.06.05 17:22

多态是虚函数来实现的,没有虚函数,基类指针没法找到子类对应的虚函数地址,就没有办法调用,实现多态

Csdn user default icon
上传中...
上传图片
插入图片