c++ primer plus阅读笔记13---虚函数 为什么要虚析构函数?
2017-08-17 17:16
232 查看
虚函数
虚函数主要是用来实现动态多态的,我们来看下边的代码:
如果没有使用关键字virtual,程序将根据引用类型或指针类型来选择方法,main函数中,b1,b2的引用类型都是Base,所以调用的是父类的function方法;
如果在父类的function的定义前边加上关键字virtual,则调用b2.function()相当于:Extends::function();
为何要使用虚函数?
加了关键字virtual以后,将会根据对象的实际类型来选择调用的函数。
我们在堆上申请一块内存存放子类的对象,并且使用父类的指针指向它,当我们是放这块内存的时候,需要调用这块内存对象的析构函数,但是我们使用的是父类的指针指向了它,如果析构函数没有不是虚析构函数,则会调用父类的析构函数,不会调用子类的析构函数。如果在子类的构造函数申请一块内存,并且在析构函数中释放这块内存,如果子类的析构函数没有被调用,将会造成内存泄露。因此需要在父类的析构函数上加上关键字virtual,这样调用析构函数的时候,会调用实际对象的类型的析构函数,如下代码:
上边这个例子阐述了虚析构函数的重要性。
虚函数主要是用来实现动态多态的,我们来看下边的代码:
class Base { ... public: void function() { ... } }; class Extends:public Base { ... public: void function() { ... } }; int main() { Base base; Extends extends; Base &b1=base; Base &b2=extends; //父类的引用指向子类,向上转型 b1.fuctione(); //相当于:Base::function(); b2.function(); //相当于:Base::function(); }
如果没有使用关键字virtual,程序将根据引用类型或指针类型来选择方法,main函数中,b1,b2的引用类型都是Base,所以调用的是父类的function方法;
如果在父类的function的定义前边加上关键字virtual,则调用b2.function()相当于:Extends::function();
class Base { public: //加了关键字virtual以后,这个函数成了虚函数,此时子类的function也成了虚函数,但是子类的virtual可以省略, virtual void function() { std::cout<<"调用了父类的function方法"<<std::endl; } }; class Extends:public Base { public: void function() { std::cout<<"调用了子类的function方法"<<std::endl; } }; int main() { Base base; Extends extends; Base &b1=base; Base &b2=extends; b1.function(); b2.function(); //相当于:Extends::function(); }
为何要使用虚函数?
加了关键字virtual以后,将会根据对象的实际类型来选择调用的函数。
我们在堆上申请一块内存存放子类的对象,并且使用父类的指针指向它,当我们是放这块内存的时候,需要调用这块内存对象的析构函数,但是我们使用的是父类的指针指向了它,如果析构函数没有不是虚析构函数,则会调用父类的析构函数,不会调用子类的析构函数。如果在子类的构造函数申请一块内存,并且在析构函数中释放这块内存,如果子类的析构函数没有被调用,将会造成内存泄露。因此需要在父类的析构函数上加上关键字virtual,这样调用析构函数的时候,会调用实际对象的类型的析构函数,如下代码:
class Base { public: virtual void function() { std::cout<<"调用了父类的function方法"<<std::endl; } ~Base() { std::cout<<"调用了父类的析构函数"<<std::endl; } }; class Extends:public Base { public: Extends() { std::cout<<"调用了子类的构造函数"<<std::endl; p=new int(20); //如果父类的析构函数不是虚析构函数,则以main函数中的方式释放内存,只调用了父类的析构函数,这块内存无法释放,造成内存泄露。 for(int i=0;i<20;i++) { *(p+i)=i; } } void function() { std::cout<<"调用了子类的function方法"<<std::endl; } void test() { std::cout<<"调用了子类的特有函数"<<std::endl; } void show() { for(int i=0;i<20;i++) { std::cout<<*(p+i)<<std::endl; } } ~Extends() { std::cout<<"调用了子类的析构函数"<<std::endl; } private: int *p; }; int main() { Base *base=new Extends(); base->function(); delete base; //销毁base指向的对象,调用其析构函数,这里只会调用父类的析构函数,造成子类中的p指针指向的内存泄露。 }
上边这个例子阐述了虚析构函数的重要性。
相关文章推荐
- 《C++ Primer Plus(第六版)》(13)(第九章 内存模型和命名空间 笔记)
- C++primer plus阅读笔记第四章
- c++ primer plus阅读笔记2---结构体共用体枚举
- c++ primer plus阅读笔记3---指针问题
- c++primer plus阅读笔记(五)
- 【学习笔记】C++primer plus 13.继承
- c++ primer plus阅读笔记10---定位new using namespace
- c++primer plus阅读笔记(六)
- c++ primer plus阅读笔记4---struct
- c++primer plus阅读笔记(七)
- c++primer plus阅读笔记(十)
- c++ primer plus阅读笔记(三)
- c++ primer plus阅读笔记6---内联函数引用变量
- C++ Primer Plus阅读笔记
- c++ primer plus阅读笔记14---虚基类
- c++ primer plus阅读笔记11---深拷贝与浅拷贝
- c++ primer plus阅读笔记7---模板特化
- c++ primer plus阅读笔记8---decltype
- c++ primer plus阅读笔记12---手动调用析构函数
- c++ primer plus笔记 [chapter 3]