虚函数

深度剖析C++析构函数

馋奶兔 提交于 2019-12-07 08:25:12
构造函数和析构函数在C 中意味着生命周期的开始和结束,它们的实现原理相同。由于析构函数往往还设置成虚函数,所以这里我重点介绍下C 析构函数的原理和各种场景。 一、析构函数的作用 当对象的生命周期结束时,会自动调用析构函数,以清理一些资源,比如释放内存、关闭文件、关闭数据库连接等等。 二、析构函数调用的时机 (1)基类析构 我们反汇编下查看上面代码: 从反汇编中可以看出,在对象离开它的作用域时,编译器自动给我们添加了一个析构函数调用的语句。 那我们使用new产生的对象会什么时候调用析构函数呢,这里我们把fun1里对象改成动态生成。 void fun1() { Base *base = new Base(); cout<<“fun1 over”<<endl; } 当我们不使用delete释放内存时,看反汇编的情况 此时,没有任何地方调用Base的析构函数 当我们使用delete释放对象时, void fun1() { Base *base = new Base(); delete base; cout<<“fun1 over”<<endl; } 我们反汇编结果: 这里我们看到析构函数调用了,这是因为当我们使用delete删除对象时,编译器会自动在后面添加一条调用析构函数的语句; 从这里我们也可以看书,C

对于虚析构函数的理解

余生颓废 提交于 2019-12-07 08:24:53
首先,对于虚析构函数,那就得说下构造函数和析构函数了。 构造函数:进行初始化成员变量的函数。 析构函数:在对象生命周期结束的时候,完成资源的回收和清理。 如果我们在设计一个类的时候,没有显示声明定义构造函数,析构函数,则编译器会自动生成。 虚析构函数:只有当一个类被定义为基类的时候,才会把析构函数写成虚析构函数。 如果我们不需要使用基类对派生类的对象操作时,我们也不必去定义虚析构函数,这样会增加系统的内存开销,当类里面有虚析构函数时,系统会为当前类分配一个虚函数表,里面存放虚函数指针,这样就会增加类的存储空间。关于虚函数表的一些知识,可以访问:http://blog.csdn.net/haoel/article/details/1948051/ 。 对于虚析构,就是在析构函数前加virtual关键字,那么到底有什么作用呢? 防止内存泄露,定义一个基类的指针p,在delete p时,如果基类的析构函数是虚函数,这时只会看p所赋值的对象,如果p赋值的对象是派生类的对象,就会调用派生类的析构函数(毫无疑问,在这之前也会先调用基类的构造函数,在调用派生类的构造函数,然后调用派生类的析构函数,基类的析构函数,所谓先构造的后释放);如果p赋值的对象是基类的对象,就会调用基类的析构函数,这样就不会造成内存泄露。 如果基类的析构函数不是虚函数,在delete p时,调用析构函数时

构造函数与析构函数中不调用虚函数

僤鯓⒐⒋嵵緔 提交于 2019-12-07 07:37:13
本文参考《effective C++》第九条款 在C++中,提倡不能在构造函数和析构函数中调用虚函数。 这是为什么呢? 首先,我们先回顾一下C++虚函数的作用。 虚函数的引入是c++运行时多态的体现,通过调用虚函数可以在运行程序时实现动态绑定,体现了面向对象编程多态的思想。 那为何提倡不能在构造函数与析构函数中不能调用虚函数。接下来我们通过代码分析在构造函数或者虚构函数中调用虚函数是否可行。 假设我们有两种商品A, B。 我们要记录着两种商品的销售记录,每当销售一种商品时,我们就要记录下来。 class item { public: item(); virtual void saleRecord() const= 0 ; //销售记录,纯虚函数 ... }; item::item() { ... virtual void saleRecord(); ... } class itemA : public item { public: itemA(); virtual void saleRecord(); ... }; class itemB : public item { public: itemB(); virtual void saleRecord(); ... }; 我们执行如下代码: itemB b; 一个derived class B 对象会被创建,

面向对象之构造函数和析构函数之三

随声附和 提交于 2019-12-07 07:35:57
题: 如果虚函数是非常有效的,我们是否可以把每个函数都声明为虚函数? 答案: 不行,这是因为虚函数是有代价的:由于每个虚函数的对象都必须维护一个v表,因此在使用虚函数的时候都会产生一个系统开销。如果仅是一个很小的类,且不想派生其他类,那么根本没必要使用虚函数。 来源: CSDN 作者: 无敌的成长日记 链接: https://blog.csdn.net/jimoshuicao/article/details/9288687

《Effective C++》item7:为多态基类声明virtual析构函数

╄→尐↘猪︶ㄣ 提交于 2019-12-07 07:34:32
今天研究了一下虚函数,解决了一直困扰的几个问题,尤其是在前段时间找工作面试的时候说不清的几个问题,早知如此,何必当初哎! Questions: (1)为什么要用虚函数? (2)为什么要定义virtual析构函数? (3)什么时候该定义virtual析构函数和什么时候不该定义virtual析构函数? Answers: (1)为什么要用虚函数? C++中的虚函数的作用主要是实现了 多态的机制 。关于多态,简而言之就是 用父类类型的指针指向其子类的实例 ,然后通过父类的指针调用实际子类的成员函数 。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。Java中的多态是通过interface和abstract来实现的,java没有virtual一说! 定义一个函数为虚函数,不代表函数为不被实现的函数。 定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。 而在Java中,只要子类实现了interface中定义的函数,那么接口声明的引用一定会调用子类的这个函数,如果子类没有定义,则调用接口中的函数! 定义一个函数为纯虚函数,才代表函数没有被实现。定义他是为了实现一个接口,起到一个规范的作用,规范继承这个。类的程序员必须实现这个函数。 先看一个 不使用virtual 的例子: 该程序先定义了一个基类:TimeKeeper,基类中有一个实现了的函数print

析构函数与virtual

别来无恙 提交于 2019-12-07 07:32:24
作为通常的原则,如果一个类定义了虚函数,那么它的析构函数就应当是virtual的。因为定义了虚函数则隐含着:这个类会被继承,并且会通过基类的指针指向子类对象,从而得到多态性。这个类可能会被继承,并且会通过基类的指针指向子类对象”,因此基类的析构函数是否为虚将决定子类的对象是否被析构。 #include <iostream.h> struct A { virtual ~A() {cout<<"~A()\n";} }; struct B: public A { ~B() {cout<<"~B()\n";} }; void main() { A* p = new B; delete p; } 如果 A 的析构函数不是virtual的,那么此时就不是先调用B的析构函数再调用A的析构函数。 输出为: ~A(); 如果 A 的析构函数为virtual,则先~B(),再~A(),输出为: ~B(); ~A(); 类如果会被派生的话,析构函数一般都应该定义为virtual的,主要不是防止内存泄露,而是为了正确的析构。如果是个封闭类(即不再被派生),就不要定义为virtual的。虚函数毕竟耗费较大的。 不用virtual 的几种情况: 作为非公有基类。仅作为 private base class 使用的 class 不需要使用虚拟析构函数。 不作为接口使用的基类。

C++虚析构函数使用场景

送分小仙女□ 提交于 2019-12-07 07:18:52
1、什么是虚函数和多态 虚函数是在类中被声明为virtual的成员函数,当编译器看到通过指针或引用调用此类函数时,对其执行晚绑定,也就是运行时多态,即通过指针(或引用)指向的类的类型信息来决定该函数是哪个类的。通常此类指针或引用都声明为基类的,它可以指向基类或派生类的对象。 编译器对每个包含虚函数的类创建一个表(称为V TA B L E)。在V TA B L E中,编译器放置特定类的虚函数地址。在每个带有虚函数的类中,编译器秘密地置一指针,称为v p o i n t e r(缩写为V P T R),指向这个对象的V TA B L E。通过基类指针做虚函数调用时(也就是做多态调用时),编译器静态地插入取得这个V P T R,并在V TA B L E表中查找函数地址的代码,这样就能调用正确的函数使晚捆绑发生。为每个类设置V TA B L E、初始化V P T R、为虚函数调用插入代码,所有这些都是自动发生的,所以我们不必担心这些。利用虚函数,这个对象的合适的函数就能被调用,哪怕在编译器还不知道这个对象的特定类型的情况下。(《C++编程思想》) 多态指同一个方法根据其所属的不同对象可以有不同的行为,即一个接口,多种实现。 2、为什么需要使用虚析构函数? 我们先来看一个例子,如下代码你认为最后的输出会是什么呢? class A { public: ~A() { cout<<

C++虚析构函数详解

喜夏-厌秋 提交于 2019-12-07 07:18:42
当派生类的对象从内存中撤销时一般先调用派生类的析构函数,然后再调用基类的析构函数。但是,如果用new运算符建立了临时对象,若基类中有析构函数,并且定义了一个指向该基类的指针变量。在程序用带指针参数的delete运算符撤销对象时,会发生一个情况:系统会只执行基类的析构函数,而不执行派生类的析构函数。 [例12.3] 基类中有非虚析构函数时的执行情况。为简化程序,只列出最必要的部分。 #include <iostream> using namespace std; class Point //定义基类Point类 { public: Point( ){} //Point类构造函数 ~Point(){cout<<"executing Point destructor"<<endl;} //Point类析构函数 }; class Circle:public Point //定义派生类Circle类 { public: Circle( ){} //Circle类构造函数 ~Circle( ){cout<<"executing Circle destructor"<<endl;} //Circle类析构函数 private: int radius; }; int main( ) { Point *p=new Circle; //用new开辟动态存储空间 delete p; /

c++ 虚析构函数的作用分析

末鹿安然 提交于 2019-12-07 07:17:55
1.为什么基类的析构函数是虚函数?    在实现多态时,当用基类指针操作派生类对象时,在析构时防止只析构基类而不析构派生类的状况发生。 什么是多态: 根据面向对象的继承规则,派生类跟基类是IS-A的关系。也就是说派生类的对象也是一个基类对象。所以基类的指针可以指向派生类的对象以便实现多态。(让基类实现多态) 亦即: 这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用; 下面看代码----------------------------------------------------------------------------------------------------------   a.第一段代码    #include<iostream> using namespace std; class ClxBase{ public : ClxBase() {}; ~ClxBase() {cout << " Output from the destructor of class ClxBase! " << endl;}; void DoSomething() { cout << " Do something in class ClxBase! " << endl; }; }; class ClxDerived : public ClxBase{

C++ 虚析构函数 纯虚析构函数 虚构造函数

南楼画角 提交于 2019-12-07 07:17:28
众所周知,在实现多态的过程中,一般将基类的析构函数设为virtual,以便在delete的时候能够多态的链式调用。那么析构函数是否可以设为纯虚呢? class CBase { public : CBase() { printf("CBase()\n"); } virtual ~CBase() = 0; }; 答案是可以,那么这样实现的目的是什么呢?当然是避免实例化。 但因为派生类不可能来实现基类的析构函数,所以 基类析构函数虽然可以标为纯虚,但是仍必须实现析构函数 ,否则派生类无法继承,也无法编译通过。 下面详细讨论: 一. 虚析构函数 我们知道,为了能够正确的调用对象的析构函数,一般要求具有层次结构的顶级类定义其析构函数为虚函数。因为在delete一个抽象类指针时候,必须要通过虚函数找到真正的析构函数。 如: [cpp] view plain copy print ? class Base { public : Base(){} virtual ~Base(){} }; class Derived: public Base { public : Derived(){}; ~Derived(){}; } void foo() { Base *pb; pb = new Derived; delete pb; } 这是正确的用法,会发生动态绑定,它会先调用Derived的析构函数