• C++ 构造函数不能声明为虚函数的原因


    构造函数不能声明为虚函数的原因有以下几点:

    1. 虚函数是为了实现多态,即通过基类的指针或引用调用派生类的成员函数。而构造函数是在创建对象时自动调用的,不可能通过基类的指针或引用去调用,因此没有多态的需求。
    2. 虚函数是通过虚函数表来实现的,每个对象都有一个虚函数表指针,指向该类的虚函数表。而对象在构造函数中才初始化虚函数表指针,如果构造函数是虚函数,就需要通过虚函数表来调用,但此时对象还没有实例化,也就没有虚函数表指针,无法找到虚函数表,因此构造函数不能是虚函数。
    3. 虚函数是在不同类型的对象产生不同的行为,而构造函数是为了初始化对象的成员变量和状态,这是对象的静态特征,不需要根据对象的类型而改变。因此构造函数没有必要是虚函数。

    你可以参考以下网页来了解更多关于这个问题的信息:

    (1) 什么函数不能声明为虚函数?_腾讯笔试题_牛客网. https://www.nowcoder.com/questionTerminal/8669335109c544679b9fa2781a6c0d6d.

    (2) (超重要)构造函数为什么不能为虚函数?析构函数为什么要虚函数?_HeisenbergWDG的博客-CSDN博客. https://blog.csdn.net/salmonwilliam/article/details/114259314.

    (3) C++ 构造函数和析构函数与virtual关键字 - CSDN博客. https://blog.csdn.net/luoxue720/article/details/75093855.

    (4) 为什么C++的构造函数不可以是虚函数,而析构函数可以是虚函数 - 知乎. https://zhuanlan.zhihu.com/p/365463954.

    (5) undefined. 《逆袭进大厂》第二弹之C++进阶篇59问59答(4W字超强汇总) - 知乎.

    1、 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的。

    问题出来了,假设构造函数是虚的,就须要通过 vtable来调用,但是对象没有实例化,也就是内存空间没有,怎么找vtable呢?所以构造函数不能是虚函数。

    2、 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到相应的调用。

    构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。

    所以构造函数没有必要是虚函数。虚函数的作用在于通过父类的指针或者引用来调用它的时候可以变成调用子类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。

    3、构造函数不须要是虚函数,也不同意是虚函数,由于创建一个对象时我们总是要明白指定对象的类型,虽然我们可能通过实验室的基类的指针或引用去訪问它但析构却不一定,我们往往通过基类的指针来销毁对象。这时候假设析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。

    4、从实现上看,vbtl构造函数调用建立,因而构造函数不可能成为虚函数从实际含义上看,在调用构造函数时还不能确定对象的真实类型(由于子类会调父类的构造函数);并且构造函数的作用是提供初始化,在对象生命期仅仅运行一次不是对象的动态行为,也必要成为虚函数

    5、当一个构造函数被调用时,它做的首要的事情之中的一个是初始化它的VPTR。

    因此,它仅仅能知道它是“当前”类的,而全然忽视这个对象后面是否还有继承者。当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码——既不是为基类,也不是为它的派生类(由于类不知道谁继承它)。所以它使用的VPTR必须是对于这个类的VTABLE。

    并且,仅仅要它是最后的构造函数调用,那么在这个对象的生命期内,VPTR将保持被初始化为指向这个VTABLE, 但假设接着另一个更晚派生的构造函数被调用,这个构造函数又将设置VPTR指向它的 VTABLE,等.直到最后的构造函数结束。

    VPTR的状态是由被最后调用的构造函数确定的。这就是为什么构造函数调用是从基类到更加派生类顺序的还有一个理由。可是,当这一系列构造函数调用正发生时,每一个构造函数都已经设置VPTR指向它自己的VTABLE。假设函数调用使用虚机制,它将仅仅产生通过它自己的VTABLE的调用,而不是最后的VTABLE(全部构造函数被调用后才会有最后的VTABLE)。

    因为构造函数本来就是为了明确初始化对象成员才产生的,然而virtual function主要是为了再不完全了解细节的情况下也能正确处理对象。另外,virtual函数是在不同类型的对象产生不同的动作,现在对象还没有产生,如何使用virtual函数来完成你想完成的动作。

    直接的讲,C++中基类采用virtual析构函数为了防止内存泄漏

    如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。

    假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而调用派生类析构函数。那么在这种情况下,派生类中申请的空间就得释放从而产生内存泄漏

    所以,为了防止这种情况的发生,C++中基类的析构函数应采用virtual虚析构函数。

  • 相关阅读:
    Prometheus服务发现之kubernetes_sd_config
    Java异常03:自定义异常及经验小结
    dp线段树优化-最大子段和
    如何将驱动编译为kernel 模块
    使用LVM方式创建linux文件系统,详细教程
    一文了解国自然热点“超级增强子”的重要标记——H3K27ac
    FPGA-1、verilog书写基本格式
    后端搜索条件
    简单方法建立个人网站,不用编程
    Postgresql下载地址及安装教程
  • 原文地址:https://blog.csdn.net/usstmiracle/article/details/132922059