l108103t
Cirfe
2015-06-05 07:35
采纳率: 35.1%
浏览 4.8k

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

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

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

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

7条回答 默认 最新

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

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

    点赞 评论
  • caozhy
    点赞 评论
  • oyljerry
    oyljerry 2015-06-05 09:22

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

    点赞 评论
  • nswcfd
    nswcfd 2015-06-05 12: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

    点赞 评论
  • CodeofWorker
    CodeofWorker 2015-06-05 08:36

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

    点赞 评论
  • zhangsong0709
    nogayy 2015-06-05 08:37

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

    点赞 评论

相关推荐