virtual用法一

#include
using namespace std;
class A{
public:virtual  void  display(){  cout<<"A"<<ENDL; }};
class B :  public A{
public:void  display(){ cout<<"B"<<ENDL; }};
void doDisplay(A *p)
{
p->display();
delete p;
}
int main(int argc,char* argv[])
{
doDisplay(new B());
return 0;
}

这段代码打印出的结果为 B ,但是当把 A 类中的 virtual 去掉之后打印出的就为 A 。当基类中没有 virtual 的时候,编译器在编译的时候把 p 看做 A 类的对象,调用的自然就是 A 类的方法。但是加上 virtual 之后,将 dispaly 方法变成了虚方法,这样调用的时候编译器会看调用的究竟是谁的实例化对象,这样就实现了多态的效果。也就是说,当基类的派生类中有重写过基类的虚方法的时候,使用基类的指针指向派生类的对象,调用这个方法实际上调用的会是派生类最后实现的方法

virtual用法二

#include
using namespace std;
class Person{public:    Person(){ cout<<"Person构造"<<ENDL; }~Person(){ cout<<"Person析构"<<ENDL; }
};
class Teacher : virtual public Person{public:    Teacher(){ cout<<"Teacher构造"<<ENDL; }~Teacher(){ out<<"Teacher析构"<<ENDL; }
};
class Student : virtual public Person{public:      Student(){ cout<<"Student构造"<<ENDL; }~Student(){ cout<<"Student析构"<<ENDL; }
};
class TS : public Teacher,  public Student{
public:            TS(){ cout<<"TS构造"<<ENDL; }~TS(){ cout<<"TS析构"<<ENDL; }
};
int main(int argc,char* argv[])
{
TS ts;
return 0;
}

这段代码的终端输出结果为:
Person构造
Teacher构造
Student构造
TS构造
TS析构
Student析构
Teacher析构
Person析构
当Teacher类和Student类没有虚继承Person类的时候,也就是把virtual去掉时候终端输出的结果为:
Person构造
Teacher构造
Person构造
Student构造
TS构造
TS析构
Student析构
Person析构
Teacher析构
Person析构

大家可以很清楚的看到这个结果明显不是我们所期望的。我们在构造TS的时候需要先构造他的基类,也就是Teacher类和Student类。而Teacher类和Student类由都继承于Person类。这样就导致了构造TS的时候实例化了两个Person类。同样的道理,析构的时候也是析构了两次Person类,这是非常危险的,也就引发出了virtual的第三种用法,虚析构,虚继承。

virtual用法三

#include
using namespace std;
class Person{public:        Person()  {name = new char[16];cout<<"Person构造"<<ENDL;}virtual  ~Person()  {delete []name;cout<<"Person析构"<<ENDL;}private:char *name;};
class Teacher :virtual public Person{
public:         Teacher(){ cout<<"Teacher构造"<<ENDL; }~Teacher(){ cout<<"Teacher析构"<<ENDL; }
};
class Student :virtual public Person{
public:         Student(){ cout<<"Student构造"<<ENDL; }~Student(){ cout<<"Student析构"<<ENDL; }
};
class TS : public Teacher,public Student{
public:             TS(){ cout<<"TS构造"<<ENDL; }~TS(){ cout<<"TS析构"<<ENDL; }
};
int main(int argc,char* argv[])
{
Person *p = new TS();
delete p;
return 0;
}

这段代码的运行结果为:
Person构造
Teacher构造
Student构造
TS构造
TS析构
Student析构
Teacher析构
Person析构
但是当我们把Person类中析构前面的virtual去掉之后的运行结果为:
Person构造
Teacher构造
Student构造
TS构造
Person析构
程序崩溃

很明显这个结果不是我们想要的程序,崩溃造成的后果是不可预计的,所以我们一定要注意在基类的析构函数前面加上virtual,使其变成虚析构在C++程序中使用虚函数,虚继承和虚析构是很好的习惯 可以避免许多的问题。

虚析构:
如果一个类用作基类,我们通常需要virtual来修饰它的析构函数,这点很重要。如果基类的析构函数不是虚析构,当我们用delete来释放基类指针(它其实指向的是派生类的对象实例)占用的内存的时候,只有基类的析构函数被调用,而派生类的析构函数不会被调用,这就可能引起内存泄露。如果基类的析构函数是虚析构,那么在delete基类指针时,继承树上的析构函数会被自低向上依次调用,即最底层派生类的析构函数会被首先调用,然后一层一层向上直到该指针声明的类型。
虚继承:

虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下:

class A

class B1:public virtual A;

class B2:public virtual A;

class D:public B1,public B2;

虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要因为这样只会降低效率和占用更多的空间。

C++中virtual的三种用法相关推荐

  1. Java中final的三种用法

    在java中final的三种用法: 1. final成员变量 2. final函数 3. final类 final成员变量 当你在类中定义变量时,在其前面加上final关键字,那便是说这个变量一旦被初 ...

  2. vue中$refs的三种用法

    我们都知道,在vue2中获取DOM元素,可以直接在元素上绑定ref属性,然后获取到DOM元素的属性值,这种方法在vue3 中仍然可以使用,但也会有一些问题.下面就介绍$refs的三种用法: 1.vue ...

  3. Mybatis中foreach的三种用法

    foreach一共有List,array,Map三种类型的使用场景. foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. item表示集合中每一个元素进行迭代时的别名, i ...

  4. mysql里collection_foreach中collection的三种用法

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...

  5. java中super的三种用法

    java中super的用法 super只在子类中出现 super有三种用法 [1] super.xxx; xxx可以是类的属性. 例如super.name;即从子类中获取父类name属性的值 [2] ...

  6. C++中using的三种用法

    1.导入命名空间 C++命名空间namespace的理解 使用C++在写不同的功能模块时,为了防止命名冲突,建议对模块取命名空间,这样在使用时就需要指定是哪个命名空间. 使用 using 导入命名空间 ...

  7. python中else的三种用法

    python中else可以在判断语句.循环语句和异常处理中使用. 判断语句 if - else - a = 3 b = 2 if a > b:print("a大于b") el ...

  8. Java中switch的三种用法方式

    从java14开始, switch语句有了一个很大的调整, 这就让swicth语句有了更多的操作和选择,在代码上,更加的简便灵活. switch 标准方式 switch - > 用法: swit ...

  9. ES6中this的三种用法

    2019独角兽企业重金招聘Python工程师标准>>> <!DOCTYPE html> <html lang="en"> <head ...

最新文章

  1. 人工智能时代下的视觉合成
  2. php MySQL快速入门_PHP 连接 MySQL
  3. Sichuan University Programming Contest 2011 Preliminary(for Non-SCUers) / M A Simple Problem
  4. win10格式化linux分区,直接删除linux分区再重装linux可以恢復启动么,我是直接在win10里把linux mint...
  5. linux网络编程之SCTP套接字常用接口
  6. php 计划任务管理,使用php管理crontab计划任务
  7. Java volatile关键字
  8. fortran调用matlab画图,[转载]Matlab与Fortran的交互--基本概念
  9. CentOS 7安装Gnome GUI 图形界面
  10. 以敏捷的方式运作一所大学
  11. Java如何比较两个数组是否相等
  12. 30个有趣的Python实战项目(附源码)
  13. 手机mstsc远程工具_mstsc远程工具
  14. 青龙脚本--今日头条极速版
  15. Java与数据结构——树(一)
  16. HTTP 请求 报错信息406
  17. Codeforces Gym 100015 简要题解
  18. 一个牛人在美国的跳槽经历(转)
  19. 自动预测保险理赔:机器学习之特征预处理(Kaggle保险索赔竞赛案例)
  20. 全网最全面的GitHub使用教程

热门文章

  1. CFA2级组合管理笔记
  2. Android 图片弹跳动画
  3. Linux上用到的一些内容整理
  4. JavaScript -函数式编程
  5. 2013中关村大数据日:大数据驱动创新
  6. github ReadMe语法
  7. 主持人百度百科词条怎么做?主持人怎么申请百科词条?
  8. C语言_公因数(公约数)、最大公因数
  9. 大学模电实验合集丨实验六 比例求和运算电路
  10. 图像的平滑滤波、边缘检测、阈值化、腐蚀膨胀等原理介绍