virtual关键字
来源:互联网 发布:淘宝店铺扣48分 编辑:程序博客网 时间:2024/09/21 06:33
virtual的使用依托于类。
1、虚函数
被virtual修饰的成员函数称为虚函数。虚函数对于多态具有决定性的作用,有虚函数才能构成多态。我们知道,基类指针可以指向派生类对象(但是基类指针只能调用基类方法),但是派生类指针不能指向基类对象(为了避免派生类指针调用了基类中没有的派生类方法)。在基类中,被virtual修饰的成员函数(如print)在派生时,如果在派生类重写了该方法print,那么在调用该方法print的时候,将是根据对象的实际类型来决定是调用基类还是派生类中的该方法print。如下:
class Base{public: virtual void print() { cout << "Base print" << endl; }};class Derive : public Base{public: void print() { cout << "Derive print" << endl; }};int main(){ Derive d; Base * b = &d; b->print();//输出 "Derive print" return 0;}
测试结果表明:在调用print的时候,基类指针b实际指向的对象是什么类型(Derive),就调用哪个类型的print(Derive中的)。下面是一个更形象的例子说明,virtual所支持的多态性。
#include <iostream>using namespace std;//军队class Troops{public: virtual void fight(){ cout<<"Strike back!"<<endl; }};//陆军class Army: public Troops{public: void fight(){ cout<<"--Army is fighting!"<<endl; }};//99A主战坦克class _99A: public Army{public: void fight(){ cout<<"----99A(Tank) is fighting!"<<endl; }};//武直10武装直升机class WZ_10: public Army{public: void fight(){ cout<<"----WZ-10(Helicopter) is fighting!"<<endl; }};//长剑10巡航导弹class CJ_10: public Army{public: void fight(){ cout<<"----CJ-10(Missile) is fighting!"<<endl; }};//空军class AirForce: public Troops{public: void fight(){ cout<<"--AirForce is fighting!"<<endl; }};//J-20隐形歼击机class J_20: public AirForce{public: void fight(){ cout<<"----J-20(Fighter Plane) is fighting!"<<endl; }};//CH5无人机class CH_5: public AirForce{public: void fight(){ cout<<"----CH-5(UAV) is fighting!"<<endl; }};//轰6K轰炸机class H_6K: public AirForce{public: void fight(){ cout<<"----H-6K(Bomber) is fighting!"<<endl; }};int main(){ Troops *p = new Troops; p ->fight(); //陆军 p = new Army; p ->fight(); p = new _99A; p -> fight(); p = new WZ_10; p -> fight(); p = new CJ_10; p -> fight(); //空军 p = new AirForce; p -> fight(); p = new J_20; p -> fight(); p = new CH_5; p -> fight(); p = new H_6K; p -> fight(); return 0;}
实验结果:
Strike back!
–Army is fighting!
—-99A(Tank) is fighting!
—-WZ-10(Helicopter) is fighting!
—-CJ-10(Missile) is fighting!
–AirForce is fighting!
—-J-20(Fighter Plane) is fighting!
—-CH-5(UAV) is fighting!
—-H-6K(Bomber) is fighting!
2、虚析构函数
实例化一个派生类对象的时候,首先将实例化基类对象,然后再实例化派生部分。同样,在销毁一个对象的时候,也希望首先调用派生类的析构函数,然后再调用基类的析构函数。如下:
//构造顺序和析构顺序class Base{public: Base() { cout << "Base" << endl; } ~Base() { cout << "Base del" << endl; }};class Derive : public Base{public: Derive() :Base() { cout << "Derive" << endl; } ~Derive() { cout << "Derive del" << endl; }};int main(){ Derive d; return 0;}
//结果:
Base
Derive
Derive del
Base del
但是,如果使用new运算符建立一个派生类临时对象(如Derive),并将该对象与基类指针关联时,那么在用delete回收动态内存的时候,将会发生一个情况:系统会只执行基类的析构函数,而不执行派生类的析构函数。
即根据上述(1、虚函数)的理论,在销毁动态内存中的派生类对象时,基类指针将调用基类的析构函数。如下:
//未用virtual修饰的基类析构函数class Base{public: Base() { cout << "Base" << endl; } ~Base() { cout << "Base del" << endl; }};class Derive : public Base{public: Derive() :Base() { cout << "Derive" << endl; } ~Derive() { cout << "Derive del" << endl; }};int main(){ Derive * d = new Derive; delete d; return 0;}
结果:
Base
Derive
Base del
但是如果用virtual来修饰析构函数,那么基类指针将首先调用派生类的析构函数,再调用基类的析构函数。
class Base{public: Base() { cout << "Base" << endl; } virtual ~Base() { cout << "Base del" << endl; }};class Derive : public Base{public: Derive() :Base() { cout << "Derive" << endl; } ~Derive() { cout << "Derive del" << endl; }};int main(){ Derive * d = new Derive; delete d; return 0;}
//结果:
Base
Derive
Derive del
Base del
基类的析构函数如果不用virtual修饰,则编译器将采用静态联编的方式,根据b的指针类型,调用相应类型的析构函数。而加上virtual后,则其后派生出来的所有类中的析构函数都为虚拟析构函数,此时编译器将采用动态联编的方式,即根据b指针实际指向的类型来决定它所调用的析构函数 。
总之,最好把基类的析构函数声明为虚函数,那么从该基类所派生的所有派生类的析构函数也都自动成为虚函数,即使派生类的析构函数与基类的析构函数名字不同。但是构造函数不能声明为虚函数。这是因为在执行构造函数时,类对象还未完成建立过程,当然谈不上函数与类对象的绑定。
3、纯虚函数
一种特殊的虚函数。在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。纯虚函数让类先具有一个操作名称,而没有操作内容,让派生类在继承时再去具体地给出定义。定义示例如下:
class Base{public: virtual void print() = 0;//声明的后面加上“=0”注释表示此函数为纯虚函数};
含有纯虚函数的类叫做抽象类。这种类不能实例化对象,只能作为基类为派生类服务。除非在派生类中完全实现基类中的所有纯虚函数,否则,派生类也是抽象类,不能实例化对象。
4、虚拟继承
即在继承的时候,除了指定公有/ 私有继承之外,可以另外通过virtual关键字来说明,在基类的多份继承中,将共享一份基类。如下:
class Base{public: Base(){}};class Derive1 : virtual public Base{public: Derive1() :Base(){}};class Derive2 : virtual public Base{public: Derive2() :Base(){}};
通过指定virtual继承,Derive1和Derive2将共享一份Base代码。如果未指定virtual继承,那么Derive1和Derive2将分别拥有一份Base代码。
- virtual 关键字
- virtual 关键字
- virtual 关键字
- virtual 关键字
- virtual 关键字
- Virtual关键字
- virtual关键字
- virtual关键字
- Virtual关键字
- virtual关键字
- C++ virtual 关键字详解
- C++ virtual关键字理解
- C# 关键字--virtual
- virtual关键字用法总结
- C#的Virtual关键字
- C++ virtual关键字理解
- C# 关键字--virtual
- C# 关键字--virtual
- Java8 Lambda表达式教程
- 五猴分桃问题详解
- JavaScript中声明全局变量的三种方式(包括显示和隐式)
- iOS关于CGContextSetBlendMode: invalid context 0x0的错误
- java基础之分解质因数练习
- virtual关键字
- cf400D
- 文章标题
- effective C++:尽量以const、enum、inline替换#define
- 视频会议及流媒体十大开源项目
- Linux内核工程导论——进程社会学
- javasscript 基础类型-- 笔记1
- Linux命令——alias
- <HTML5秘籍>——第6章(美妙的CSS3字体和特效)