虚函数 纯虚函数 虚基类说明
原文:http://www.cnblogs.com/ms-frank/archive/2008/01/16/1041310.html
虚基类
在说明其作用前先看一段代码
- class A
- {
- public:
- int iValue;
- };
- class B:public A
- {
- public:
- void bPrintf(){cout<<"This is class B"<<endl;};
- };
- class C:public A
- {
- public:
- void cPrintf(){cout<<"This is class C"<<endl;};
- };
- class D:public B,public C
- {
- public:
- void dPrintf(){cout<<"This is class D"<<endl;};
- };
- void main()
- {
- D d;
- cout<<d.iValue<<endl; //错误,不明确的访问
- cout<<d.A::iValue<<endl; //正确
- cout<<d.B::iValue<<endl; //正确
- cout<<d.C::iValue<<endl; //正确
- }
class A { public:int iValue; }; class B:public A { public:void bPrintf(){cout<<"This is class B"<<endl;}; }; class C:public A { public:void cPrintf(){cout<<"This is class C"<<endl;}; }; class D:public B,public C { public:void dPrintf(){cout<<"This is class D"<<endl;}; }; void main() {D d;cout<<d.iValue<<endl; //错误,不明确的访问cout<<d.A::iValue<<endl; //正确cout<<d.B::iValue<<endl; //正确cout<<d.C::iValue<<endl; //正确 }
从代码中可以看出类B C都继承了类A的iValue成员,因此类B C都有一个成员变量iValue ,而类D又继承了B C,这样类D就有一个重名的成员 iValue(一个是从类B中继承过来的,一个是从类C中继承过来的).在主函数中调用d.iValue 因为类D有一个重名的成员iValue编译器不知道调用 从谁继承过来的iValue所以就产生的二义性的问题.正确的做法应该是加上作用域限定符 d.B::iValue 表示调用从B类继承过来的iValue。不过 类D的实例中就有多个iValue的实例,就会占用内存空间。所以C++中就引用了虚基类的概念,来解决这个问题。
- class A
- {
- public:
- int iValue;
- };
- class B:virtual public A
- {
- public:
- void bPrintf(){cout<<"This is class B"<<endl;};
- };
- class C:virtual public A
- {
- public:
- void cPrintf(){cout<<"This is class C"<<endl;};
- };
- class D:public B,public C
- {
- public:
- void dPrintf(){cout<<"This is class D"<<endl;};
- };
- void main()
- {
- D d;
- cout<<d.iValue<<endl; //正确
- }
class A { public:int iValue; }; class B:virtual public A { public:void bPrintf(){cout<<"This is class B"<<endl;}; }; class C:virtual public A { public:void cPrintf(){cout<<"This is class C"<<endl;}; }; class D:public B,public C { public:void dPrintf(){cout<<"This is class D"<<endl;}; }; void main() {D d;cout<<d.iValue<<endl; //正确 }
在继承的类的前面加上virtual关键字表示被继承的类是一个虚基类,它的被继承成员在派生类中只保留一个实例。例如iValue这个成员,从类 D这个角度上来看,它是从类B与类C继承过来的,而类B C又是从类A继承过来的,但它们只保留一个副本。因此在主函数中调用d.iValue时就不 会产生错误。
虚函数
还是先看代码
- class A
- {
- public:
- void funPrint(){cout<<"funPrint of class A"<<endl;};
- };
- class B:public A
- {
- public:
- void funPrint(){cout<<"funPrint of class B"<<endl;};
- };
- void main()
- {
- A *p; //定义基类的指针
- A a;
- B b;
- p=&a;
- p->funPrint();
- p=&b;
- p->funPrint();
- }
class A { public:void funPrint(){cout<<"funPrint of class A"<<endl;}; }; class B:public A { public:void funPrint(){cout<<"funPrint of class B"<<endl;}; }; void main() {A *p; //定义基类的指针A a;B b;p=&a;p->funPrint();p=&b;p->funPrint(); }
大家以为这段代码的输出结果是什么?有的人可能会马上回答funPrint of class A 与 funPrint of class B 因为第一次输出是引用类A的实 例啊,第二次输出是引用类B的实例啊。那么我告诉你这样想就错啦,答案是funPrint of class A 与 funPrint of class A 至于为什么输出 这样的结果不在本文讨论的范围之内;你就记住,不管引用的实例是哪个类的当你调用的时候系统会调用左值那个对象所属类的方法。比如说 上面的代码类A B都有一个funPrint 函数,因为p是一个A类的指针,所以不管你将p指针指向类A或是类B,最终调用的函数都是类A的funPrint 函数。这就是静态联篇,编译器在编译的时候就已经确定好了。可是如果我想实现跟据实例的不同来动态决定调用哪个函数呢?这就须要用到 虚函数(也就是动态联篇)
- class A
- {
- public:
- virtual void funPrint(){cout<<"funPrint of class A"<<endl;};
- };
- class B:public A
- {
- public:
- virtual void funPrint(){cout<<"funPrint of class B"<<endl;};
- };
- void main()
- {
- A *p; //定义基类的指针
- A a;
- B b;
- p=&a;
- p->funPrint();
- p=&b;
- p->funPrint();
- }
class A { public:virtual void funPrint(){cout<<"funPrint of class A"<<endl;}; }; class B:public A { public:virtual void funPrint(){cout<<"funPrint of class B"<<endl;}; }; void main() {A *p; //定义基类的指针A a;B b;p=&a;p->funPrint();p=&b;p->funPrint(); }
在基类的成员函数前加virtual关键字表示这个函数是一个虚函数,所谓虚函数就是在编译的时候不确定要调用哪个函数,而是动态决定将要调 用哪个函数,要实现虚函数必须派生类的函数名与基类相同,参数名参数类型等也要与基类相同。但派生类中的virtual关键字可以省略,也表 示这是一个虚函数。下面来解决一下代码,声明一个基类的指针(必须是基类,反之则不行)p,把p指向类A的实例a,调用funPrint函数,这 时系统会判断p所指向的实例的类型,如果是A类的实例就调用A类的funPrint函数,如果是B类的实例就调用B类的funPrint函数。
纯虚函数
与其叫纯虚函数还不如叫抽象类,它只是声明一个函数但不实现它,让派生类去实现它,其实这也很好理解。
- class Vehicle
- {
- public:
- virtual void PrintTyre()=0; //纯虚函数是这样定义的
- };
- class Camion:public Vehicle
- {
- public:
- virtual void PrintTyre(){cout<<"Camion tyre four"<<endl;};
- };
- class Bike:public Vehicle
- {
- public:
- virtual void PrintTyre(){cout<<"Bike tyre two"<<endl;};
- };
- void main()
- {
- Camion c;
- Bike b;
- b.PrintTyre();
- c.PrintTyre();
- }
class Vehicle { public:virtual void PrintTyre()=0; //纯虚函数是这样定义的 }; class Camion:public Vehicle { public:virtual void PrintTyre(){cout<<"Camion tyre four"<<endl;}; }; class Bike:public Vehicle { public:virtual void PrintTyre(){cout<<"Bike tyre two"<<endl;}; }; void main() {Camion c;Bike b;b.PrintTyre();c.PrintTyre(); }
如上代码,定义了一个交通工具类(Vehicle),类中有一函数可打印出交通工具的轮胎个数,但交通工具很多轮胎个数自然也就不确定,所以 就把它定义为纯虚函数,也就是光定义函数名不去实现它,类Camion继承了Vehicle并实现了里面的代码,打印出有4个轮胎。Bike类也是一样。 有一点须要注意一下,纯虚函数不能实化化,但可以声明指针。
总结
虚基类
1, 一个类可以在一个类族中既被用作虚基类,也被用作非虚基类。
2, 在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的子对象。
3, 虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。
4, 最派生类是指在继承结构中建立对象时所指定的类。
5, 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的缺省构造函数。
6, 从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生 类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象 只初始化一次。
7, 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。
虚函数
1, 虚函数是非静态的、非内联的成员函数,而不能是友元函数,但虚函数可以在另一个类中被声明为友元函数。
2, 虚函数声明只能出现在类定义的函数原型声明中,而不能在成员函数的函数体实现的时候声明。
3, 一个虚函数无论被公有继承多少次,它仍然保持其虚函数的特性。
4, 若类中一个成员函数被说明为虚函数,则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时 ,对该成员函数调用可采用动态联编。
5, 定义了虚函数后,程序中声明的指向基类的指针就可以指向其派生类。在执行过程中,该函数可以不断改变它所指向的对象,调用不同 版本的成员函数,而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。 纯虚函数 版本的成员函数,而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。
纯虚函数
1, 当在基类中不能为虚函数给出一个有意义的实现时,可以将其声明为纯虚函数,其实现留待派生类完成。
2, 纯虚函数的作用是为派生类提供一个一致的接口。
3, 纯虚函数不能实化化,但可以声明指针。
虚函数 纯虚函数 虚基类说明相关推荐
- C++中为什么要引入抽象基类和纯虚函数?
为什么要引入抽象基类和纯虚函数? 主要目的是为了实现一种接口的效果. 抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层. ⑴抽象类的定义:带有纯虚函数的类为抽象类. ...
- c++ 纯虚成员函数+抽象基类
公共接口是指一系列成员函数的集合,支持该接口的类必须以合适的方式重新定义这些成员函数,否则就无法创建对象.C++ 中可以通过抽象基类来实现公共接口,为了介绍抽象基类,我们需要先来了解一下纯虚成员函数. ...
- C++引入抽象基类和纯虚函数的作用和目的
为什么要引入抽象基类和纯虚函数? 主要目的是为了实现一种接口的效果. 原文链接:https://blog.csdn.net/weibo1230123/article/details/82014322 ...
- [C++] - 纯虚函数 抽象基类 接口类
翻译自:https://www.learncpp.com/cpp-tutorial/126-pure-virtual-functions-abstract-base-classes-and-inter ...
- python虚函数_Python进阶话题杂谈(十三)纯虚函数与抽象基类
纯虚函数与抽象类都是Python面向对象中重要的编程范式,用于对继承类做强制性接口实现约定. abc模块包含了一系列与抽象基类与纯虚函数相关的方法.Python中通过修改元类进行抽象基类的设定.这里P ...
- 基类、派生类、虚基类、虚函数、虚析构、纯虚函数、抽象类
基类:被其它类通过继承方式作为父类继承的类称为基类:描述派生类的统一种类的方式. 派生类:通过继承其他类(并可能含有自定义成员)实现的子类:为提高代码的重用性及与同样继承于同一个父类的其它类形成统一种 ...
- c++中的虚特性(虚基类、虚函数、纯虚函数)
1. 虚基类 1.1 虚基类作用 为了解决多继承时的命名冲突和冗余数据问题,使得派生类中只保留一份间接基类的成员. 其本质是是让某个类做出声明,承诺愿意共享它的基类.其中,这个被共享的基类就称为虚基类 ...
- 38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】
虚函数.虚基类.纯虚函数 (一).虚函数 1.什么是虚函数: 2.虚函数的格式: 3.关于虚函数的注意事项: 4.虚函数的作用: 5.虚函数访问格式 6.虚函数的各种疑难杂症 [当指针是基类.但虚函数 ...
- C++多继承中重写不同基类中相同原型的虚函数
在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: virtual void TestA(); }; class ...
- C++虚继承和虚基类;虚函数与继承
ref http://blog.csdn.net/owen7500/article/details/52432970?locationNum=4&fps=1 http://blog.csdn. ...
最新文章
- java适配器各三种_适配器三种
- php数组交集 效率,PHP数组交集的优化
- 注册中心—组件—Eureka
- java 回调函数很好懂
- C#Word转Html的类
- 《马克思主义基本原理概论》复习笔记
- buildroot 执行 make savedefconfig 错误解决
- ORACLE大数据查询
- Centos 6.x 更新内核 2.6-4.13
- 对过去五年工作经历的总结
- oracle open_cursors参数配置
- 如何将论文图表做得漂亮?
- 优达棒球赛数据分析项目
- 自动化工业机器人涂胶程序
- java 内存 pdf_jvm内存模型高清版.pdf
- sql判断字段是否以某个子串开头,结尾
- 浏览器踩坑:浏览器访问已发布服务器的网址显示跨域,但微信浏览器可以正常访问,别人的浏览器也可以正常访问
- 存储芯片NAND FLASH的封装
- Python背单词记单词小程序,可自定义词库,支持多种记忆模式,根据词义拼写、选择单词,根据词意选择单词
- pyecharts加载不出html图片,已解决
热门文章
- Process.On--------在线画图工具(流程图、UI图、脑图等)
- 电商物流SOP文档的5个注意事项
- python 自动批改 PDF 作业
- 腾讯视频涨价:一年多赚74亿!关注我领取腾讯VIP会员,周卡低至7元
- Windows资源管理器浏览svg图片
- [业余知识:PC 硬件监控]使用WinRing0 2.0.0.20读取CPU温度
- oracle over的用法;
- 计算机专业暑假计划,2021计算机专业考研备考:暑期复习规划
- 基于python2+selenium3+pytest4的UI自动化框架
- 内网穿透、将本地服务暴露到外网、三分钟搞定!!!