#include<iostream>
using namespace std;
class Base{
public:
void m()
{
cout << "it's Base's m() " << endl;
}
virtual void f()
{
cout << "it's Base's f()" << endl;
}
};
class Sub: public Base
{
void m()
{
cout << "it's Sub's m()" << endl;
}
void f()
{
cout << "it's Sub's f()" << endl;
}
};
void main()
{
Base* base = new Sub;
base->f();
base->m();
}

上述是以Base为基类,并且Sub派生了Base,同时复写了两个函数f(),m()

当在主函数main里用Base类型的指针指向Sub类型对象,此时利用Base指针调用f()和m(),那么这个时候问题就来了。

在默认情况下Base类的指针会调用当前类型的方法,也就是Base::f(),Base::m(),那么应该输出的都是Base方法中的语句

然而结果输出的是

为什么会产生这种原因呢?

因为父类的f()是虚函数,那么当基类指针调用它的派生类对象时,会默认调用多态性对象的相应方法,于是就解释了为什么Base* base->f()调用了派生类Sub的f()的方法,

由此我们可以知道虚函数Virtual主要是为了解决多态性问题,因为一个基类方法定义后,它的派生类对象会针对此方法进行不同的覆盖实现,即多态性,若你此时利用基类的指针来指向基类的多态性子类,那么就需要利用virtual修饰基类方法,从而可以来调用你所需要的派生类的方法而避免了调用基类的此方法。

Virtual是C++ OO机制中很重要的一个关键字。在类Base中加了Virtual关键字的函数就是虚拟函数(例如函数print),于是在Base的派生类Derived中就可以通过重写虚拟函数来实现对基类虚拟函数的覆盖。当基类Base的指针point指向派生类Derived的对象时,对point的print函数的调用实际上是调用了Derived的print函数而不是Base的print函数。这是面向对象中的多态性的体现。

还有虚函数析构函数,应用在这样一个问题:在基类为抽象类,并且基类指针指向派生类,想要删除这个基类指针指向的内存时

先看第一种情况

 de<iostream>
using namespace std;
class Base{
public:
Base()
{
}
~Base()
{
cout << "Base has deleted" << endl;
}
};
class Sub: public Base
{
public:
Sub()
{
}
~Sub()
{
cout << "Sub has delete" << endl;
}
};
void main()
{
Base* base = new Sub;
delete base;
base = NULL;
}

看运行结果

此时是用基类Base指针去操作继承类Sub,在delete Base*指针后,我们可以从结果得到只调用了基类的析构函数,但是派生类的析构函数并没有调用,这相当于内存只是删除了一一半,还有一半内存为删除,导致了内存泄漏,此时则需要用到虚析构函数,来达到调用派生类的析构函数来删除内存空间的目的,也就是下面这种情况:

 #include<iostream>
using namespace std;
class Base{
public:
Base()
{
}
virtual ~Base()
{
cout << "Base has deleted" << endl;
}
};
class Sub: public Base
{
public:
Sub()
{
}
~Sub()
{
cout << "Sub has delete" << endl;
}
};
void main()
{
Base* base = new Sub;
delete base;
base = NULL;
}

运行结果如下图所示

此时我们可以看到在基类析构函数加了Virtual变成虚函数后,成功地调用了基类和派生类的析构函数,从而实现了基类指针指向内存的完全释放。

虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。

但是有一点要注意,当某个类没有虚函数时,那么此类不会被当作基类,此时定义虚析构函数只会增加内存开销,因为需要开启一个虚函数列表来储存。

以上只是个人的小总结,若有错误,欢迎前来纠正!

C++ virtual虚函数的更多相关文章

  1. 【2016-10-13】【坚持学习】【Day4】【virtual 虚函数】

    定义一个基类,有一个虚函数 定义三个子类,分别继承,重写,New,这个虚函数   abstract class Test { public virtual void Prinf() { Console ...

  2. C++\virtual 虚函数、纯虚函数

    前提摘要: 虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 虚函数定义: 指向基类的指针或引用在操作它的多态类(子类/派生类)对象时,会根据不同的类对象, ...

  3. 23.C++- 继承的多种方式、显示调用父类构造函数、父子之间的同名函数、virtual虚函数

     上章链接: 22.C++- 继承与组合,protected访问级别 继承方式 继承方式位于定义子类的”:”后面,比如: class Line : public Object //继承方式是publi ...

  4. C#语法-虚方法详解 Virtual 虚函数

    虚方法 / Virtual 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享. ...

  5. c++中virtual 虚函数

    转载: https://www.cnblogs.com/weiyouqing/p/7544988.html 在面向对象的C++语言中,虚函数(virtual function)是一个非常重要的概念. ...

  6. 104.virtual虚函数多态与异构数据结构

    #include "mainwindow.h" #include <QApplication> #include <list> #include <Q ...

  7. C++之虚函数和多态

    干货较多-需要自己深思理解: C++支持两种多态性: 1.编译时多态性(静态绑定-早绑定) 在程序编译阶段即可以确定下来的多态性 通过使用 重载机制(重载函数)实现 (模板)http://blog.c ...

  8. TControl的显示函数(5个非虚函数,4个虚函数)和三个例子的执行过程(包括SetParent的例子)

    // 9个显示函数 procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); virtual; // 虚函数,important 根据父控 ...

  9. c++ 深入理解虚函数

    为什么使用虚函数?什么是虚函数?虚函数是为了解决什么问题? 面向对象的三大特征: 封装 多态 继承 普通虚函数 虚析构函数 纯虚函数 抽象类 接口类 隐藏 vs 覆盖 隐藏与覆盖之间的关系 早绑定和晚 ...

随机推荐

  1. 使用Uploadify(UploadiFive)多文件上传控件遇到的坑

    最近项目中需要实现多文件上传功能,于是结合需求最终选择了Uploadify这一款控件来实现.相比其他控件,Uploadify具有简洁的界面,功能API基本可以解决大多数需求,又是基于jquery的,配 ...

  2. Web API 自动生成帮助文档并使用Web API Test Client 测试

    之前在项目中有用到webapi对外提供接口,发现在项目中有根据webapi的方法和注释自动生成帮助文档,还可以测试webapi方法,功能很是强大,现拿出来与大家分享一下. 先看一下生成的webapi文 ...

  3. 交换排序---快速排序算法(Javascript版)

    快速排序是对冒泡排序的一种改进.通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行 ...

  4. ASP.NET MVC显示HTML字符串

    一些html经HtmlEncode后,如“<span>测试数据</span>”.现需要把这些内容正常显示于asp.net mvc的视图内. 举个例子来解决与说明,先创建一个mo ...

  5. ASP.NET中Request.RawUrl、Request.Url的区别

    如果访问的地址是: http://hovertree.com/guestbook/addmessage.aspx?key=hovertree%3C&n=myslider#zonemenu 那么 ...

  6. 关于CodeFirst异常:无法确定类型'XXX'和类型‘YYY’之间的关联的主体端,必须使用关系 Fluent API 或数据注释显式配置此关联的主体端。

    此错误的原因是,你配置两个实体间的关系为一对一 然而我认为的一对一关系是,两者之间必须存在一个主体, 也就是说,你不能表1的外键是表2的主键并且表1的主键是表2的外键, 这样不符合数据库式吧? 我想多 ...

  7. mysql分页查询详解

    我们做的后端项目一般都会有admin管理端,当管理端将要展示数据的时候,就需要用到分页.所以分页的考查在面试中也相当多.在mysql中进行分页查询时,一般会使用limit查询,而且通常查询中都会使用o ...

  8. bootstrap框架禁用谷歌字体

    bootstrap框架禁用谷歌字体 H5框架换字体.png

  9. CI框架源码阅读笔记6 扩展钩子 Hook.php

    CI框架允许你在不修改系统核心代码的基础上添加或者更改系统的核心功能(如重写缓存.输出等).例如,在系统开启hook的条件下(config.php中$config['enable_hooks'] = ...

  10. JS复杂对象克隆

    之前一直比较习惯用Ext.apply()方法来实现对象的克隆,今天遇到一个问题,当对象中含有数组,且数组中包含复杂类型时,Ext.apply()的克隆就有问题了. 于是就想着试试自己能不能解决.在网上 ...