构造函数调用虚函数的问题

构造函数调用虚函数的问题

大家好,又见面了,我是全栈君。

一般情况下,不允许在构造函数或者析构函数中调用虚函数。其实语法上都没有问题,只是会失去多态性。

 

如果在构造函数中调用虚函数,会先调用父类中的实现,也就失去了多态的性质。

class A {
    public:
    virtual void print() {
        cout << "A" << endl;
    }
    A() {
        print();
    }
    ~A() {
        //print();
    }
};
class B :public A {
    void print() {
        cout << "B" << endl;
    }
};
int main() {
    A* ptr = new B;
    return 0;
}

 构造函数调用虚函数的问题

如果在析构函数中调用虚函数,也是同样的失去了多态性。

class A {
    public:
    virtual void print() {
        cout << "A" << endl;
    }
    A() {
        print();
    }
    ~A() {
        print();
    }
};
class B :public A {
    void print() {
        cout << "B" << endl;
    }
};
int main() {
    A* ptr = new B;
    delete ptr;
    return 0;
}

 

 构造函数调用虚函数的问题

 

 

 

 

出现上述结果的原因是因为,构造函数还没有将vptr和vtable初始化完毕,就调用虚函数,此时必然调用的基类中的实现。

而在析构函数中,因为子类的那部分已经被析构掉了,此时在父类的析构函数调用虚函数,调用的也只能是父类中的实现。


 

但是吧,也有的文章说如果一个类为基类的时候,必须将析构函数写为虚函数,否则子类那部分无法释放。

https://blog.csdn.net/starlee/article/details/619827 

我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:    
    有下面的两个类:

class ClxBase
{

public:
    ClxBase() {};
    virtual ~ClxBase() {};

    virtual void DoSomething() { cout << “Do something in class ClxBase!” << endl; };
};

class ClxDerived : public ClxBase
{

public:
    ClxDerived() {};
    ~ClxDerived() { cout << “Output from the destructor of class ClxDerived!” << endl; }; 

    void DoSomething() { cout << “Do something in class ClxDerived!” << endl; };
};
    代码

ClxBase *pTest = new ClxDerived;
pTest->DoSomething();
delete pTest;
    的输出结果是:

Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
    这个很简单,非常好理解。
    但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:

Do something in class ClxDerived!
    也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。我想所有的C++程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。
    所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
    当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

转载于:https://www.cnblogs.com/LUO77/p/5907297.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/108862.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Struts2之—实现自己的结果集的定义ajax

    Struts2之—实现自己的结果集的定义ajax

    2022年1月10日
    39
  • 基于SSM框架的网上购物商城及电商后台管理系统

    基于SSM框架的网上购物商城及电商后台管理系统基于SSM框架的网上购物商城及电商后台管理系一、开发环境操作环境:Windows10开发工具:IDEA数据库:MySQL服务器:TomCat二、系统功能介绍前台商城功能注册登录:用户首先要填写相关信息,注册为会员。修改个人信息:用户登录后可以修改个人信息。查看公告和留言反馈网站:用户可查看公告,登录后可以给网站留言反馈网站问题。浏览商品:会员浏览网上商城,可以根据分类检索、关键字检索、热销商品和折扣商品浏览商品和商品信息及评价。管理购物车:登录后会员可以将想购买的商品加入购物

    2022年6月5日
    37
  • 优先级队列的使用[通俗易懂]

    优先级队列的使用[通俗易懂]优先级队列(priorityqueue)中的元素可以按照任意的顺序插入,却总是按照排序的顺序进行检索。也就是说,无论何时调用remove方法,总会获得当前优先级队列中最小的元素.然后,优先级队列并没有对所有的元素进行排序。如果用迭代的方式处理这些元素,并不需要对它们进行排序。优先级队列使用了一个优雅且高效的数据结构,称为堆(heap)。堆事一个可以自我调整的二叉树,对树执行添加(add)和删除(

    2022年9月16日
    0
  • k8s的apiserver_kube_apiserver

    k8s的apiserver_kube_apiserverAPIserverfunc main() { … #核心 command := app.NewAPIServerCommand() #日志 logs.InitLogs() defer logs.FlushLogs() …}#NewAPIServerCommand#核心是调用run函数 运行AIPserver 永远不会退出return Run(completedOptions, genericapiserver.SetupSignalHandler())#Run#创建

    2022年8月9日
    4
  • 局域网文件传输方式分析

    局域网文件传输方式分析一、概述在C/S结构的软件开发过程中通常被限于局域网范围内, 常常会遇到需要传输数据文件、音视频文件、升级文件到服务器端或者客户端。每个工作站点都是通过交换机或者集线器、路由器等设备相互连接在一起。由于需要传输的站点数量、局域网环境、OS系统的不同,传输上的性能上也有很大的区别, 传输方式也是多种多样的,比如常见的局域网共享传输、基于FTP协议传输、点对点传输等方式。不同的网络操作系统(NOS

    2022年6月4日
    34
  • mybatis的逆向工程怎么实现_列举创建连接的方法

    mybatis的逆向工程怎么实现_列举创建连接的方法Mybatis逆向工程创建方法1.首先利用数据库的可视化工具新建一张表。2.打开IDEA新建一个项目。3.导入pom.xml所需要的依赖文件。&amp;lt;?xmlversion=&quot;1.0&quot;encoding=&quot;UTF-8&quot;?&amp;gt;&amp;lt;projectxmlns=&quot;http://maven.apache.org/POM/4.0.0&quo

    2022年8月21日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号