美文网首页
未重写的父类函数调用已重写的函数

未重写的父类函数调用已重写的函数

作者: 李相赫的乐芙兰 | 来源:发表于2018-11-12 19:09 被阅读24次

    最近在写跨服组队的功能,需要重构组队匹配的代码,在开发的过程中,遇到一个父类函数中的某一步调用需要被子类重写的问题,为了重写的函数能被正确调用,做了一下实验,结果如下:

    class A{
    public:
        void Foo();
        void Foo0();
        virtual void Foo1();
        void Foo2();
    };
    
    void A::Foo(){
        Foo0();
        Foo1();
    }
    void A::Foo0(){
        cout<<"aaa000\n";
    }
    void A::Foo1(){
        cout<<"aaa111\n";
    }
    void A::Foo2(){
        cout<<"aaa222\n";
    }
    
    class B:public A{
    public:
        void Foo0();
        virtual void Foo1();
        void Foo2();
    };
    
    void B::Foo0(){
        cout<<"bbb000\n";
    }
    void B::Foo1(){
        cout<<"bbb111\n";
    }
    void B::Foo2(){
        cout<<"bbb222\n";
    }
    
    int main(){
        A tmp_a;
        B tmp_b;
        tmp_a.Foo();///aaa000 aaa111
        tmp_b.Foo();///aaa000 bbb111
        /*子类调用未重写的父类函数Foo,Foo继续调用子类已重写的函数:
        若该函数是普通函数(Foo0),则仍然调用父类的实现;若该函数是虚函数(Foo1),则调用子类的实现*/
    
        tmp_a.Foo2();///aaa222
        tmp_b.Foo2();///bbb222
    
        tmp_a = tmp_b;
        tmp_a.Foo();///aaa000 aaa111
        /*当我们用子类的对象给基类的对象赋值或者初始化基类的对象时,
        它的本质就是将从父类继承来的数据成员的值赋给父类的对象,
        而此时子类对象中的其他数据将会被截断,也就是丢失*/
    
        A* p_a = new B;
        p_a->Foo();///aaa000 bbb111
        /*如果用父类指针指向子类对象,
        那么父类指针也只能访问到父类所拥有的数据成员和成员函数,
        而无法访问到子类所独有的数据成员和成员函数。*/
    
        A& iter_a = tmp_b;
        iter_a.Foo();///aaa000 bbb111
        /*引用和指针类似*/
    
        return 0;
    }
    

    总结:
    1.子类调用未重写的父类函数Foo,Foo继续调用子类已重写的函数:若该函数是普通函数(Foo0),则仍然调用父类的实现;若该函数是虚函数(Foo1),则调用子类的实现

    2.当我们用子类的对象给基类的对象赋值或者初始化基类的对象时,它的本质就是将从父类继承来的数据成员的值赋给父类的对象,而此时子类对象中的其他数据将会被截断,也就是丢失

    3.如果用父类指针指向子类对象,那么父类指针也只能访问到父类所拥有的数据成员和成员函数,而无法访问到子类所独有的数据成员和成员函数。

    4.另外注意一下基类指针的回收问题。当用基类指针指向子类从堆中分配的对象时,如下形式 A*p = new B;当调用delete p;p=NULL;销毁对象时,是调用父类A的析构函数还是调用子类B的构造函数呢?如下图所示:答案是会调用父类的构造函数,这样问题就来了,子类不是从父类继承来的那些独有的成员变量的内存将得不到释放,将会造成内存泄露,这种情况应该如何避免内存泄露呢?这就需要使用虚析构函数。

    虚析构函数就是在父类的析构函数前加上virtual关键字,这种特性将会被继承下去,也即子类的析构函数也为虚析构函数

    虚析构函数的使用场合:当存在继承关系,用父类的指针指向从堆中分配的子类的对象时,然后又想用父类的指针去释放掉内存,就会用到虚析构函数,用了虚析构函数后,就会先调用子类的析构函数,再调用父类的构造函数了

    相关文章

      网友评论

          本文标题:未重写的父类函数调用已重写的函数

          本文链接:https://www.haomeiwen.com/subject/placfqtx.html