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

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

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关键字,这种特性将会被继承下去,也即子类的析构函数也为虚析构函数

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

你可能感兴趣的:(未重写的父类函数调用已重写的函数)