继承关系中的构造函数,析构函数与虚函数一文全析

继承关系中的构造函数,析构函数与虚函数一文全析

1. 无虚析构函数的public继承

#include<iostream>
#include<vector>
using namespace std;
class P{
public:
    P(){cout<<"construct P!"<<endl;}
    ~P(){cout<<"deconstruct P!"<<endl;}
};
class C: public P{
public:
    C(){cout<<"construct C!"<<endl;}
    ~C(){cout<<"deconstruct P!"<<endl;}
};

1.1 栈上构造子类

int main(){
    C c;
    return 0;
}

construct P!
construct C!
deconstruct C!
deconstruct P!

1.2 堆上构造子类指针指向子类对象

int main(){
    C *pointer = new C();
    delete pointer;  // 无此不会调用析构函数
    return 0;
}

construct P!
construct C!
deconstruct C!
deconstruct P!

1.3 堆上构造父类指针指向子类对象

int main(){
    P* point = new C();
    delete point;
    return 0;
}

construct P!
construct C!
deconstruct P!

2. 有虚析构函数的public继承

#include<iostream>
#include<vector>
using namespace std;
class P{
public:
    P(){cout<<"construct P!"<<endl;}
    virtual ~P(){cout<<"deconstruct P!"<<endl;}
};
class C: public P{
public:
    C(){cout<<"construct C!"<<endl;}
    ~C(){cout<<"deconstruct P!"<<endl;}
};

1.3 堆上构造父类指针指向子类对象

代码同1.3

construct P!
construct C!
deconstruct C!
deconstruct P!

概念辨析:函数隐藏,函数覆盖,函数重写,函数重载

  • 函数隐藏(Function Hiding):基类的非虚函数在子类中有同名函数,就称为基类函数被隐藏了

  • 函数覆盖/重写(Function Overriding):在派生类中重新定义基类中已有的函数,函数名、参数列表和返回值类型都必须与基类中的函数相同。当通过基类指针或引用调用该函数时,将会调用派生类中的函数,而不是基类中的函数。

  • 函数重载(Function Overloading):在同一个作用域内,定义多个同名但参数列表不同的函数,可以根据传入的参数类型和数量来确定调用哪个函数。函数重载可以提高代码的可读性和复用性。

在多态下,虚函数是通过虚函数表来实现的。每个对象都有一个指向虚函数表的指针,虚函数表中存储了该类的虚函数地址。当子类重写父类的虚函数时,子类会在自己的虚函数表中存储自己的虚函数地址,这样在运行时,通过对象的虚函数表指针就可以定位到子类的虚函数。 而非虚函数在编译时就已经确定了调用的函数地址,不会在运行时进行动态绑定。因此,即使子类重写了父类的非虚函数,也无法通过对象的指针来定位到子类的函数。只有通过强制类型转换将对象转换为子类类型,才能调用子类的函数。https://www.cnblogs.com/malecrab/p/5572730.html

在析构函数中一样,如果析构函数不是虚函数,那么就在编译期间根据指针类型静态绑定到父类的析构函数上,与子类无关。但如果是虚析构函数,那么会发生动态绑定,在运行期间根据实际对象绑定到子类的析构函数,于是就是先析构子类在析构父类,否则只会析构父类。

posted @ 2023-08-31 11:45  石中火本火  阅读(27)  评论(0编辑  收藏  举报