virtual用法一:多态

 #include<iostream>
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 ;
}

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

virtual用法二: 虚继承:解决数据冗余

 #include<iostream>
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 ;
}

这段代码的终端输出结果为:

 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<iostream>
using namespace std;
class Person{
public: Person() {name = new char[];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 ;
}

这段代码的运行结果为:

 Person构造
Teacher构造
Student构造
TS构造
TS析构
Student析构
Teacher析构
Person析构

但是当我们把Person类中析构前面的virtual去掉之后的运行结果为:

 Person构造
Teacher构造
Student构造
TS构造
Person析构
程序崩溃

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

原文:https://blog.csdn.net/jirryzhang/article/details/79392934

C++学习---- virtual的三种用法的更多相关文章

  1. virtual 三种用法

    virtual用法一 #include using namespace std;class A{public:     virtual  void  display(){  cout<<& ...

  2. using 的三种用法

    using 有哪三种用法? 1)引入命名空间. 2)给命名空间或者类型起别名. 3)划定作用域.自动释放资源,使用该方法的类型必须实现了 System.IDisposable接口,当对象脱离作用域之后 ...

  3. 学习Python的三种境界

    前言 王国维在<人间词话>中将读书分为了三种境界:"古今之成大事业.大学问者,必经过三种之境界:'昨夜西风凋碧树,独上高楼,望尽天涯路'.此第一境也.'衣带渐宽终不悔,为伊消得人 ...

  4. Js闭包常见三种用法

        Js闭包特性源于内部函数可以将外部函数的活动对象保存在自己的作用域链上,所以使内部函数的可以将外部函数的活动对象占为己有,可以在外部函数销毁时依然存有外部函数内的活动对象内容,这样做的好处是可 ...

  5. .NET(c#)new关键字的三种用法

    前几天去家公司面试,有一道这样的题:写出c#中new关键字的三种用法,思前想后挖空心思也只想出了两种用法,回来查了下msdn,还真是有第三种用法:用于在泛型声明中约束可能用作类型参数的参数的类型,这是 ...

  6. SQL、LINQ、Lambda 三种用法(转)

    SQL.LINQ.Lambda 三种用法颜色注释: SQL LinqToSql Lambda QA1. 查询Student表中的所有记录的Sname.Ssex和Class列.select sname, ...

  7. c# new关键字的三种用法

    三种用法如下: 在 C# 中,new 关键字可用作运算符.修饰符或约束. 1)new 运算符:用于创建对象和调用构造函数. 2)new 修饰符:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成 ...

  8. java中 this 的三种用法

    Java中this的三种用法 调用属性 (1)this可以调用本类中的任何成员变量 调用方法(可省略) (2)this调用本类中的成员方法(在main方法里面没有办法通过this调用) 调用构造方法 ...

  9. 子查询。ANY三种用法。ALL两种用法。HAVING中使用子查询。SELECT中使用子查询。

    子查询存在的意义是解决多表查询带来的性能问题. 子查询返回单行多列: ANY三种用法: ALL两种用法: HAVING中的子查询返回单行单列: SELECT中使用子查询:(了解就好,避免使用这种方法! ...

随机推荐

  1. box-shadow的应用技巧

    一.box-shadow的参数解析 box-shadow:none; box-shadow: h-shadow v-shadow blur spread color inset; box-shadow ...

  2. Docker官方文档翻译2

    转载请标明出处: https://blog.csdn.net/forezp/article/details/80158062 本文出自方志朋的博客 容器 准备工作 安装Docker,版本为1.13或者 ...

  3. Python 学习笔记(七)Python字符串(一)

    字符串 字符串或串(String)是由数字.字母.下划线组成的一串字符,用双引号或单引号包裹的为字符串 1 >>> "hello world" 2 'hello ...

  4. 菜鸟崛起 DB Chapter 2 MySQL 5.6的概述与安装

    在上文菜鸟崛起 DB Chapter 1 数据库概述我们初步认识了数据库,也知道市面上常见的几种数据库,下面我们就针对常见的MySQL数据库展开对DataBase的探讨. 2.1  MySQL介绍 M ...

  5. win7 bat copy 一个文件 到另外的文件夹内,路径得用引号哦

    win 7 的 用引号 把路径引起来 ,但是win10 的可以不用哦 !

  6. Python基础—02-数据类型

    数据类型 存储单位 最小单位是bit,表示二进制的0或1,一般写作b 最小的存储单位是字节,用byte表示,1B = 8b 1024B = 1KB 1024KB = 1MB 1024MB = 1GB ...

  7. Oracle PL/SQL中异常高级特性

    在OraclePL/SQL语句块中exception的异常处理部分是非常重要的组成部分,它决定了在PL/SQL语句块内部可执行部分在发生异常错误时,程序是友好地提示:程序遇到某些错误而无法执行,还是抛 ...

  8. navicat 链接oracle时出现的各种问题

    1.出现12514错误: 方法:在oracle的安装路径下找到tnsnames.ora文件(我的安装路径为E:\app\sa\product\12.2.0\dbhome_1\network\admin ...

  9. boost::shared_ptr文档翻译

    shared_ptr: 共享所有权 原文链接 描述 模版类 shared_ptr 存储动态构造对象的指针,通常是由C++ new语句完成的.这个对象指针在最后一个持有指针所有权的shared_ptr被 ...

  10. 【前行】◇第3站◇ Codeforces Round #512 Div2

    [第3站]Codeforces Round #512 Div2 第三题莫名卡半天……一堆细节没处理,改一个发现还有一个……然后就炸了,罚了一啪啦时间 Rating又掉了……但是没什么,比上一次好多了: ...