为什么C++不能有虚构造函数,却可以有虚析构函数

本文探讨了C++中虚函数的实现机制及其在运行时动态绑定的应用,特别是对于析构函数的重要性。通过示例代码说明了如何通过虚析构函数确保派生类对象能正确释放资源。
class B{ 

public : 

   virtualvoid m1(); 

   virtualvoid m2(); 

}; 

class D : public B{ 

    virtualvoid m1(); 

} 

一、C++的动态绑定使用vtable(虚成员函数表)来实现。vtable支持运行时查询,使系统可以将某一函数名绑定到vtable的特定入口地址。

例如上段代码的虚函数表为:

虚成员函数       入口地址      虚成员函数            入口地址
B::m1          0x7723         
D::m1                        0x99a7            //重定义的

B::m2          0x23b4         
D::m2                        0x23b4            //完全继承
  • 由于系统执行虚函数时,要从对象的vtable找到函数入口地址,而且vtable是存储于对象的内存空间中。假如对象没有实例化,就找不到vtable。因此,构造函数不能是vittual。

  • 但是,析构函数一般都需要加上virtual,假如定义Base *b = new Deriver; Deriver是Base的子类,并且~Base()不为virtual。那么当对象被注销时,系统只会调用~Base(),而不会调用~Deriver(),因为b是Base类型,已被静态绑定析构函数。如果基类或子类用new创建了内存空间,就必须通过析构函数销毁。因此必须使用vitual析构函数,实现动态绑定。

  • 另外:从另一个角度也可以看出构造函数不能为虚函数,1,虚函数的作用在于通过父类的指针或者引用调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类或者引用去调用,因此就规定构造函数不能是虚函数。

二、构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我们可能通过实验室的基类的指针或引用去访问它

但析构却不一定,我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数


#include <iostream>

using namespace std;

class A
{
public:
    A()
    {
        cout << "A" << endl;
    }
    ~A()
    {
        cout << "~A" << endl;
    }
};

class B:public A
{
public:
    B()
    {
        cout << "B" << endl;
    }
    ~B()
    {
        cout << "~B" << endl;
    }
};

class C:public B
{
public:
    C()
    {
        cout << "C" << endl;
    }
    ~C()
    {
        cout << "~C" << endl;
    }
};

int main()
{
    A *b = new B;
    cout << endl;
    A *c = new C;
    cout << endl;

    delete b;
    cout << endl;
    delete c;
    return 0;
}

这里写图片描述

析构函数加上 virtual 后:
这里写图片描述

抽象类是面向对象编程中的一个重要概念,它不能被实例化,只能作为基类被继承。抽象类通常包含一个或多个纯虚函数,这些函数没有实现,必须在派生类中实现。抽象类的特点包括: 1. **不能实例化**:抽象类不能创建对象,只能作为基类被继承。 2. **包含纯虚函数**:至少包含一个纯虚函数,这些函数没有实现,必须在派生类中实现。 3. **提供接口**:抽象类通常用于定义接口,强制派生类实现特定的功能。 4. **支持多态**:通过抽象类可以实现多态性,派生类可以重写基类的虚函数,从而实现不同的行为。 在C++中,构函数和析构函数可以是虚函数吗? 1. **构函数不能是虚函数**:C++中构函数不能是虚函数,因为构函数在对象创建时调用,而虚函数表在对象创建后才初始化。 2. **析构函数可以是虚函数**:析构函数可以是虚函数,通常建议将基类的析构函数定义为虚函数,以确保在删除派生类对象时能够正确调用派生类的析构函数,防止资源泄漏。 ```cpp class Base { public: virtual ~Base() { std::cout << "Base destructor called" << std::endl; } }; class Derived : public Base { public: ~Derived() { std::cout << "Derived destructor called" << std::endl; } }; int main() { Base* obj = new Derived(); delete obj; // 输出: Derived destructor called 然后输出: Base destructor called return 0; } ``` 在这个例子中,`Base`类的析构函数是虚函数,因此在删除`Derived`类对象时,会先调用`Derived`类的析构函数,然后再调用`Base`类的析构函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值