×

构造函数和析构函数可以是虚函数

构造函数和析构函数可以是虚函数(为什么C++的构造函数不可以是虚函数,而析构)

admin admin 发表于2024-09-24 23:35:12 浏览5 评论0

抢沙发发表评论

大家好,构造函数和析构函数可以是虚函数相信很多的网友都不是很明白,包括为什么C++的构造函数不可以是虚函数,而析构也是一样,不过没有关系,接下来就来为大家分享关于构造函数和析构函数可以是虚函数和为什么C++的构造函数不可以是虚函数,而析构的一些知识点,大家可以关注收藏,免得下次来找不到哦,下面我们开始吧!

本文目录

为什么C++的构造函数不可以是虚函数,而析构

1、为什么构造函数不可以是虚函数①从存储空间角度虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。②从使用角度虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。③构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我们可能通过实验室的基类的指针或引用去访问它。但析构却不一定,我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。④从实现上看,vbtl在构造函数调用后才建立,因而构造函数不可能成为虚函数 从实际含义上看,在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有太大的必要成为虚函数⑤当一个构造函数被调用时,它做的首要的事情之一是初始化它的V P T R。因此,它只能知道它是“当前”类的,而完全忽视这个对象后面是否还有继承者。当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码- -既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。所以它使用的V P T R必须是对于这个类的V TA B L E。而且,只要它是最后的构造函数调用,那么在这个对象的生命期内, V P T R将保持被初始化为指向这个V TA B L E, 但如果接着还有一个更晚派生的构造函数被调用,这个构造函数又将设置V P T R指向它的 V TA B L E,等.直到最后的构造函数结束。V P T R的状态是由被最后调用的构造函数确定的。这就是为什么构造函数调用是从基类到更加派生 类顺序的另一个理由。但是,当这一系列构造函数调用正发生时,每个构造函数都已经设置V P T R指向它自己的 V TA B L E。如果函数调用使用虚机制,它将只产生通过它自己的V TA B L E的调用,而不是最后的V TA B L E(所有构造函数被调用后才会有最后的V TA B L E)。2、为什么析构函数可以是虚函数编译器总是根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候,C++不管这个指针指向一个基类对象还是一个派生类的对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数的代码来释放资源,而没有重载析构函数,那么会有资源泄漏。所以建议的方式是将析构函数声明为虚函数。如果你使用MFC,并且以CObject或其派生类为基类,那么MFC已经为你做了这件事情;CObject的析构函数是虚函数。一个函数一旦声明为虚函数,那么不管你是否加上virtual 修饰符,它在所有派生类中都成为虚函数。但是由于理解明确起见,建议的方式还是加上virtual 修饰符。C++不把虚析构函数直接作为默认值的原因是虚函数表的开销以及和C语言的类型的兼容性。有虚函数的对象总是在开始的位置包含一个隐含的虚函数表指针成员。如果是对于MFC类CPoint和CSize这样的小型类,增加一个指针就增加了很多内存占用,而且使得其内存表示和基类POINT和SIZE不一致。

c++什么是虚函数,构造与析构函数可以是虚函数吗

虚函数是用是实现多态。也可以为将来升级程序带来好处析构函数可以是虚的构造函数不行

构造函数和析构函数可以是虚函数吗

构造函数不能声明为虚函数,析构函数可以声明为虚函数,而且有时是必须声明为虚函数。不建议在构造函数和析构函数里面调用虚函数。构造函数不能声明为虚函数的原因是:1 构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的。而在构造一个对象时,由于对象还未构造成功。编译器无法知道对象 的实际类型,是该类本身,还是该类的一个派生类,或是更深层次的派生类。无法确定。。。2 虚函数的执行依赖于虚函数表。而虚函数表在构造函数中进行初始化工作,即初始化vptr,让他指向正确的虚函数表。而在构造对象期间,虚函数表还没有被初 始化,将无法进行。虚函数的意思就是开启动态绑定,程序会根据对象的动态类型来选择要调用的方法。然而在构造函数运行的时候,这个对象的动态类型还不完整,没有办法确定它到底是什么类型,故构造函数不能动态绑定。(动态绑定是根据对象的动态类型而不是函数名,在调用构造函数之前,这个对象根本就不存在,它怎么动态绑定?)编译器在调用基类的构造函数的时候并不知道你要构造的是一个基类的对象还是一个派生类的对象。析构函数设为虚函数的作用: 解释:在类的继承中,如果有基类指针指向派生类,那么用基类指针delete时,如果不定义成虚函数,派生类中派生的那部分无法析构。 例:#include "stdafx.h"#include "stdio.h"class A{public:A();virtual~A();};A::A(){}A::~A(){printf("Delete class APn");}class B : public A{public:B();~B();};B::B(){ }B::~B(){printf("Delete class BPn");}int main(int argc, char* argv){A *b=new B;delete b;return 0;} 输出结果为:Delete class BDelete class A如果把A的virtual去掉:那就变成了Delete class A也就是说不会删除派生类里的剩余部分内容,也即不调用派生类的虚函数因此在类的继承体系中,基类的析构函数不声明为虚函数容易造成内存泄漏。所以如果你设计一定类可能是基类的话,必须要声明其为虚函数。正如Symbian中的CBase一样。Note:1. 如果我们定义了一个构造函数,编译器就不会再为我们生成默认构造函数了。2. 编译器生成的析构函数是非虚的,除非是一个子类,其父类有个虚析构,此时的函数虚特性来自父类。3. 有虚函数的类,几乎可以确定要有个虚析构函数。4. 如果一个类不可能是基类就不要申明析构函数为虚函数,虚函数是要耗费空间的。5. 析构函数的异常退出会导致析构不完全,从而有内存泄露。最好是提供一个管理类,在管理类中提供一个方法来析构,调用者再根据这个方法的结果决定下一步的操作。6. 在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。7.在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。8. 记得在写派生类的拷贝函数时,调用基类的拷贝函数拷贝基类的部分,不能忘记了。

c++析构函数、构造虚定义为虚函数的问题

1不是不能定义,是定义了没意义。因为构造函数不被继承,而虚函数是要在派生类中重定义的2定义虚析构函数后,由于多态,当使用基类指针指向派生类对象时,会调用派生类的虚构函数,然后派生类的析构函数自动调用基本析构函数。不是虚的话,直接调用基类的析构函数了。如果派生类中有用new分配的内存,就无法释放了

C++构造,析构函数可以是虚函数吗,是否可以被继承

构造函数不能为虚函数,析构函数则可以,在C++中函数没有继承一说,继承指的是类继承,派生类的构造函数执行时需先构造基类的构造函数,而析构函数的执行顺序则刚好相反。

关于虚函数的说法不正确的是()

关于虚函数的说法不正确的是() A.基类中的虚函数可为派生类继承,继承下来仍是虚函数B.虚函数重新定义时必须保证其返回值和参数个数及类型与基类中的项一致C.虚函数必须是类的一个成员函数D.析构函数和构造函数都可以是虚函数,都可以被继承正确答案:D

析构函数为什么是虚函数

析构函数可以为虚函数,也可以不为虚函数。(更多的时候不为虚函数)。设计析构函数为虚函数,主要是考虑到继承。

析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。

函数介绍

与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统会自动执行析构函数。以C++语言为例:析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,例如~stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。

构造、析构函数可否为virtual

构造函数不能声明为虚函数,析构函数可以声明为虚函数,而且有时是必须声明为虚函数。不建议在构造函数和析构函数里面调用虚函数。构造函数不能声明为虚函数的原因是:解释一:所谓虚函数就是多态情况下只执行一个。而从继承的概念来讲,总是要先构造父类对象,然后才能是子类对象。如果构造函数设为虚函数,那么当你在构造父类的构造函数时就不得不显示的调用构造。还有一个原因就是为了防错,试想如果你在子类中一不小心重写了个跟父类构造函数一样的函数,那么你的父类的构造函数将被覆盖,也即不能完成父类的构造.就会出错。解释二:虚函数的主要意义在于被派生类继承从而产生多态。派生类的构造函数中,编译器会加入构造基类的代码,如果基类的构造函数用到参数,则派生类在其构造函数的初始化列表中必须为基类给出参数,就是这个原因。虚函数的意思就是开启动态绑定,程序会根据对象的动态类型来选择要调用的方法。然而在构造函数运行的时候,这个对象的动态类型还不完整,没有办法确定它到底是什么类型,故构造函数不能动态绑定。(动态绑定是根据对象的动态类型而不是函数名,在调用构造函数之前,这个对象根本就不存在,它怎么动态绑定?)编译器在调用基类的构造函数的时候并不知道你要构造的是一个基类的对象还是一个派生类的对象。析构函数设为虚函数的作用: 解释:在类的继承中,如果有基类指针指向派生类,那么用基类指针delete时,如果不定义成虚函数,派生类中派生的那部分无法析构。例:#include "stdafx.h" #include "stdio.h" class A { public: A(); virtual ~A(); }; A::A() { } A::~A() { printf("Delete class AP/n"); } class B : public A { public: B(); ~B(); }; B::B() { } B::~B() { printf("Delete class BP/n"); } int main(int argc, char* argv) { A *b=new B; delete b; return 0; } 输出结果为:Delete class B Delete class A 如果把A的virtual去掉:那就变成了Delete class A因此在类的继承体系中,基类的析构函数不声明为虚函数容易造成内存泄漏。所以如果你设计一定类可能是基类的话,必须要声明其为虚函数。正如Symbian中的CBase一样。Note:1. 如果我们定义了一个构造函数,编译器就不会再为我们生成默认构造函数了。2. 编译器生成的析构函数是非虚的,除非是一个子类,其父类有个虚析构,此时的函数虚特性来自父类。3. 有虚函数的类,几乎可以确定要有个虚析构函数。4. 如果一个类不可能是基类就不要申明析构函数为虚函数,虚函数是要耗费空间的。5. 析构函数的异常退出会导致析构不完全,从而有内存泄露的问题。最好是提供一个管理类,在管理类中提供一个方法来析构,调用者再根据这个方法的结果决定下一步的操作。6. 在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化,如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的,所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。但是不是说你不可以那么写程序,你这么写,编译器也不会报错。只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。7. 在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。8. 记得在写派生类的拷贝函数时,调用基类的拷贝函数拷贝基类的部分,不能忘记了。如果一个类是作为基类使用,那么他的虚构函数一定要是虚的,即用virtual关键字(参数为零则为纯虚函数).否则会有内存泄漏(很重要),因为当用基类的指针删除一个派生类的对象时,要调用派生类的析构函数.但是其子类或者子子类可以的析构函数可以是虚函数,也可以不是虚函数.(不加virtual 关键字则不会调用派生类的析构函数,而上面用了ClxBase *pTest = new ClxDerived;语句也就是new的ClxDerived对象没有 销毁,所以产生内存泄漏)2.类中的虚函数,如果一个类中的函数被声明成为虚函数,那么其子类不用在声明为虚函数(当子类还有子类时),也可以声明为虚函数.结果是一样的.同虚析构函数的道理是一样的.当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

c++什么是虚函数,构造与析构函数可以是虚函数吗_百度知道

定义虚函数是为了允许用基类的指针来调用派生类的这个函数。(实现了多态的特性)构造函数不可以是虚函数,因为虚函数的存储空间(虚函数表)初始化是在构造函数中(你想象一下,实例化的时候,虚构造函数的话,构造函数等自身来调用初始化不就矛盾了吗)析构函数需要申明成虚函数,在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生(如果基类的析构函数不是虚函数,释放指向派生类的基类指针时,就只会执行基类的析构函数,而不会去调用派生的析构函数)

为什么C++的构造函数不可以是虚函数,而析构的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于为什么C++的构造函数不可以是虚函数,而析构、为什么C++的构造函数不可以是虚函数,而析构的信息别忘了在本站进行查找哦。