-
虚基类的作用、使用及抽象基类虚析构函数问题
2020-03-06 10:21:15虚基类解决的问题: 当存在基类A,类B与C派生自A,类D派生自类B与C时,类D中存在...如何使用虚基类: //.h Class A {}; Class B:public virtual A {...}; //此时类A称为类B的虚基类 Class C:virtual public A {...};...1、虚基类:
虚基类解决的问题:
当存在基类A,类B与C派生自A,类D派生自类B与C时,类D中存在两个类A对象导致二义性问题。
二义性问题还有如:对象d不知道调用哪个类B或类C中均存在的func()方法。如何使用虚基类:
//.h Class A {}; Class B:public virtual A {...}; //此时类A称为类B的虚基类 Class C:virtual public A {...}; //此时类A称为类C的虚基类 Class D:public B,public C{...};
此时类D的实例化对象中只存在一个类A对象,因此不存在二义性问题。这是C++定义的新语法,以不增加新关键字为原则因此使用了virtual作为修饰符。
//.cpp D::D(const A& a,variable x,variable y,...):A(a),B(a,x),C(a,y){} D::D(const B& b,variable x,variable y,...):A(b),B(b,x),C(b,y){} 将类B对象b给与类A与类C构造函数,因为其基类均是A, 基类引用可以指向派生类,因此不存在问题。
普通的多重继承,派生类只能调用上一级基类(即时基类)的构造函数,但在虚继承问题中,类D必须直接调用类A的构造函数(语法规定),对于非虚基类,则直接调用非法。
a) 虚继承会增加大小、速度、初始化复杂度等成本,应该经历避免虚继承与多重继承。
2、抽象基类:
包含纯虚函数的类称为抽象类,抽象类不能够实例化,至少包含一个纯虚函数的类称为抽象类。
纯虚函数:将虚函数声明结尾处为=0,不进行函数定义,如://.h Class A{ public: A() {} virtual show(); //在cpp文件中实现 virtual express() = 0; //纯虚函数 不需要实现 virtual ~A(); //cpp中实现 };
纯虚析构函数:当需要定义一个抽象类,而类中又没有其他纯虚函数,因为至少包含一个纯虚函数才能成为抽象类,因此可以将虚析构函数设置为纯虚的。
//.h Class A{ public: A() {} ... virtual ~A() = 0; }; //.cpp A::~A() {}
注:纯虚析构函数必须提供定义(其他的不需要),因为派生类析构时,需要调用基类的析构函数,所以要保证为它提供函数体。如果不这么做,链接器就会报错。
参考资料: C++ Primer Plus 14.3多重继承 与 Effective C++条款7为多态基类声明虚析构函数
总结:
1、虚基类是针对派生时的基类而言的,单独看类A不存在虚基类的说法。
2、virtual 和 public 两个修饰符的位置可以互换。
3、基类A可以为抽象类也可以为普通类
4、在派生类中直接调用虚基类构造函数。
5、虽然抽象类的析构函数可以是纯虚函数,但必须提供析构函数的定义。 -
车辆类多重继承中使用虚基类
2014-02-21 10:19:34【项目3】在下面一段类的定义中,自行车类的虚基类为车辆类,机动车类的虚基类也为车辆类,摩托车类的基类为自行车类和机动车类,类之间均为公有继承。 (1)根据上面各类间关系的描述,补全下面程序段中空缺的代码...【项目3】在下面一段类的定义中,自行车类的虚基类为车辆类,机动车类的虚基类也为车辆类,摩托车类的基类为自行车类和机动车类,类之间均为公有继承。
(1)根据上面各类间关系的描述,补全下面程序段中空缺的代码
(2)实现程序中声明的成员函数,注意相应操作中的动作发生的条件不能满足时应给出提示。
(3)运行程序,享受开摩托的过程。(请下载资源中一个可执行文件,可以先运行再编程。不必申请驾照,这个摩托车很安全。)(4)在报告中回答问题:本题中使用虚基类的好处是什么?
#include <iostream> #include<conio.h> #include <windows.h> using namespace std; enum vehicleStaus {rest, running}; //车辆状态:泊车、行进 class vehicle //车辆类 { protected: int maxSpeed; //最大车速 int currentSpeed; //当前速度 int weight; //车重 vehicleStaus status; //rest-泊车状态;running-行进状态 public: vehicle(int maxS, int w); //构造函数,初始时,当前速度总为0且处在停车状态 void start(); //由rest状态到running, 初速为1 void stop(); //由running状态到rest, 当前速度小于5时,才允许停车 void speed_up(); //加速,调用1次,速度加1 void slow_down(); //减速,调用1次,速度减1,速度为0时,停车 int GetSpeed1(){return maxSpeed;} int GetSpeed2(){return currentSpeed;} int GetWeight(){return weight;} vehicleStaus GetStatus(){return status;} }; vehicle::vehicle(int maxS, int w):maxSpeed(maxS),weight(w),currentSpeed(0),status(rest){} void vehicle::start(){status=running;currentSpeed=1;} void vehicle::stop(){if(currentSpeed<5)status=rest;} void vehicle::speed_up(){if(currentSpeed<maxSpeed)++currentSpeed;} void vehicle::slow_down(){if(currentSpeed>0)--currentSpeed;} class bicycle :virtual public vehicle//(1)自行车类的虚基类为车辆类 { protected: double height; //车高 public: bicycle(int maxS=10, int w=50, int h=0.7); //定义构造函数 double GetHeight(){return height;} }; bicycle::bicycle(int maxS, int w, int h):vehicle(maxS, w),height(h){} class motorcar :virtual public vehicle //(2)机动车类的虚基类也为车辆类 { protected: int seatNum; //座位数 int passengerNum; //乘客人数 public: motorcar(int maxS=150, int w=1500, int s=5, int p=1); //定义构造函数 void addPassenger(int p=1); //增加搭载的乘客,超员要拒载,有人下车时,p为负数。当然车上乘客至少有1个(司机)。只有车停稳后才能上下客。 int GetSeat(){return seatNum;} int GetPassenger(){return passengerNum;} }; motorcar::motorcar(int maxS, int w, int s, int p):vehicle(maxS, w),seatNum(s),passengerNum(p){} void motorcar::addPassenger(int p) { if(passengerNum+p>seatNum) {cout<<"超了.."<<endl;passengerNum=seatNum;} else if(passengerNum+p<0) {cout<<"没了。。"<<endl;passengerNum=0;} else passengerNum+=p; } class motorcycle: public bicycle,public motorcar//(3)摩托车类的基类为自行车类和机动车类 { public: //定义构造函数 motorcycle(int maxS=90, int w=100, int s=3, int p=1, int h=0.7); void show(); //显示摩托车的运行状态 }; motorcycle::motorcycle(int maxS, int w, int s, int p, int h)//虚基类必须直接初始化 :vehicle(maxS, w),bicycle(maxS,w,h),motorcar(maxS,w,s,p){} void motorcycle::show() { cout<<endl; cout<<"最大速度:"<< GetSpeed1() <<endl; cout<<"当前速度:"<< GetSpeed2() <<endl; cout<<"车子重量:"<< GetWeight() <<endl; cout<<"车子状态:"<< GetStatus() <<endl; cout<<"车子高度:"<< GetHeight()<<endl; cout<<"车子座位:"<< GetSeat()<<endl; cout<<"车子乘客:"<< GetPassenger()<<endl; } int main( ) { motorcycle m; bool end=false; while (!end){ cout<<"请操作:1-启动 2-加速 3-减速 4-有人上车 5-有人下车 6-停车 0-结束"<<endl; char keydown= _getch(); //_getch()返回键盘上读取的字符 switch(keydown) { case '1': cout<<"操作(启动)\t"; m.start(); break; case '2': cout<<"操作(加速)\t"; m.speed_up(); break; case '3': cout<<"操作(减速)\t"; m.slow_down(); break; case '4': cout<<"操作(有人上车)\t"; m.addPassenger(); break; case '5': cout<<"操作(有人下车)\t"; m.addPassenger(-1); break; case '6': cout<<"操作(停车)\t"; m.stop(); break; case '0': end=true; break; } m.show(); cout<<endl; Sleep(200); //要包含头文件<windows.h> } return 0; }
-
虚基类、虚函数、抽象类
2019-03-19 10:51:43使用虚基类,可以使得在派生类中只保留间接基类的一份成员。 声明虚基类只需要在继承方式前面加上 virtual 关键字 虚函数 成员函数前面加virtual关键字,基类的虚函数不用实现,派生时再具体实现 抽象类 虚函数...虚基类
使用虚基类,可以使得在派生类中只保留间接基类的一份成员。
声明虚基类只需要在继承方式前面加上 virtual 关键字
虚函数
成员函数前面加virtual关键字,基类的虚函数不用实现,派生时再具体实现
抽象类
虚函数等于0,不能实例化
-
C++虚基类时使用以及构造函数的特殊之处
2020-11-18 21:44:46//在多重派生中如果希望公共的基类在派生类中只有一个拷贝,可将此基类说明为虚基类 ...//而且只有最远派生类的对虚基类的构造函数使用有效,之前的都是无效的,而且构造函数只能被调用一次; //虚基类 /* class bas//在多重派生中如果希望公共的基类在派生类中只有一个拷贝,可将此基类说明为虚基类 //virtual public base0 //如果虚基类的构造函数是默认或者缺省够造函数那么后面的派生类则无需对虚基类的构造函数进行调用了 //需要注意的是如果虚基类中没有默认构造函数,或者中间的派生类采用的不是默认构造函数或者有参数,那么在所有的派生类中必须都要有虚基类构造函数的说明 //而且只有最远派生类的对虚基类的构造函数使用有效,之前的都是无效的,而且构造函数只能被调用一次; //虚基类 /* class base0 { public: int var0; base0(int var0) ; }; base0::base0(int var0) { this->var0 = var0; } class base1:virtual public base0 { public: int var1; base1(int var0,int var1); }; base1::base1(int var0,int var1):base0(var0) { this->var1 = var1; } class base2 :virtual public base0 { public: int var2; base2(int var0, int var2); }; base2::base2(int var0, int var2) :base0(var0) { this->var2 = var2; } class base3:public base1,public base2 { public: base3(int var0, int var1, int var2,int var3); }; base3::base3(int var0, int var1, int var2, int var3): base0(var3),base1(var0,var1),base2(var2,var3) { } int main() { base3 b(1, 2, 3, 4); cout << "b.base1.var0:" << b.base1::var0 << endl; cout << "b.base2.var0:" << b.base2::var0 << endl; b.base1::var0 = 10; cout << "b.base2.var0:" << b.base2::var0 << endl; system("pause"); } */
-
虚基类的初始化
2017-05-02 17:14:43使用虚基类时,虚基类时被共享的,也就是在继承体系中无论被继承多少次,对象内存模型中均只会出现一个虚基类的子对象,即使共享虚基类。但是必须要有一个类来完成基类的初始化,同时还不能够重复进行初始化。C++... -
虚基类 java_java,C#接口与C++的虚基类
2021-02-27 14:12:33最长公共子序列PK最长公共...而最长公共子序列则并不要求连续. (1)递归方法求最长公共子序列的长度 1) ...02.Apache FtpServer使用数据库管理用户1.创建数据库及表 使用\apache-ftpserver-1.0.6\res\ft... -
虚基类与多重继承
2016-10-15 22:09:41在说明虚基类之前,不得不提多重继承(MI)的概念。...对于第二个问题,可以使用虚基类来解决。虚基类使得从多个类(它们的基类相同)派生出的对象只继承一个基类对象。虚基类使用方法://Worker被用 -
多重继承-虚基类
2020-08-05 15:50:25虚基类多重继承具有相同祖先的普通基类继承具有相同祖先的虚基类继承虚基类声明关于虚基类合理的创建标题,有助于目录的生成如何改变文本的样式如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容... -
虚基类的使用
2011-05-10 14:10:00<br />今天看到一本书上有关于虚基类的实现,看了之后猛然发现,自己以前在项目中也遇到这样的问题。当时不明白原因,只是通过别的方式解决了。其实核心思想就是由于多个父类造成的。看上面的用例关系图,一般... -
C++ 虚基类表指针字节对齐
2017-09-26 22:07:00在这里我使用了一个空类K,不要被这个东西所迷惑,我使用这个空类的目的主要是为了让它产生虚基类表指针而又不引入虚基类成员变量,这样我就可以少叙述一些关于虚基类成员排放的东西,而将焦点聚集在引入的那个虚... -
虚基类解决副本重复
2019-05-27 18:24:38虚基类 对于前面同名隐藏和二义...但是在大多数情况下,我们不需要两个同名副本,只需要保留一个即可,C++提供了虚基类技术来解决此问题。 在前面的例子中,当我们定义一个派生类对象c时,它会构造B1类,B2类,B... -
继承与派生——虚基类
2012-03-09 13:57:06虽然也可以通过在成员变量名前面加上“类名::”消除其二义性,但解决这个问题的最好办法是使用虚基类。虚基类方法可以保证在任何一个存在公共基类的派生类中,不会存在一个以上的同名成员变量。 所谓虚基类,就是... -
C++ 虚基类
2016-10-03 12:43:121. 当派生类的多个直接基类中某个成员名称相同,派生类访问这个成员时,如果不指定基类名,编译器无法判断该成员来自哪一个基类。 class Base1{ protected: int a; public: void set(int x):a(x){} }; class ... -
C++ 虚继承 虚基类 多继承 详细解读
2020-03-26 01:02:52首先要说一下多继承,虚基类和虚继承都是在多继承的一种情况下存在的内容。 多继承是子类继承自多个父类的继承方式。 但是在多继承的过程中,存在这样一种情况,一个基类A分别被中间基类B、C继承,然后D又继承了B... -
c++复习(3)虚函数,虚基类,虚继承与多继承
2020-08-25 11:22:02目录前言虚函数虚基类虚继承与多继承题目题目1输入输出样例输入样例输出代码题目2输入输出样例输入样例输出代码 前言 继续复习c++ 虚函数 ...未使用虚函数,不能正确调用 class animal { public: vo -
虚基类继承中的析构函数问题
2019-07-04 23:17:42虚基类继承中的析构函数问题 在很多教材里面对虚基类继承的构造函数...实验1:使用派生类指针指向派生类对象,析构函数不加virtual #include <iostream> class A { public: A() { }; ~A() { std::cout ... -
【选择恐惧症】接口?虚基类?
2016-11-16 10:15:42记得有个朋友跟我讨论过这样的一个问题,说到他刚刚学习接口和虚基类的相关知识时觉得很迷茫,不知道什么时候该用接口,什么时候该使用虚基类。后来慢慢地发现接口能做的事情,虚基类也能够实现,甚至有更多的特点。... -
在保护继承中基类的共有成员_C++学习刷题17--虚继承与虚基类
2021-01-05 19:44:09一、前言本部分为C++语言刷题系列中的第17节,主要讲解这几个知识点:多继承的二义性问题、虚继承与虚基类。欢迎大家提出意见、指出错误或提供更好的题目!二、知识点讲解知识点1: 多继承中存在的二义性问题,分成... -
虚基类及派生类的构造函数
2011-12-09 12:16:07而不是按初始化列表的次序调用3调用派生类子对象的构造函数,按子对象的次序调用,不按初始化列表的次序调用,4执行派生类的构造数 5virtual是虚基类的关键字,使用虚基类的进行派生类声明时内存中积累成员只会存在... -
C++学习笔记 -虚基类_hawkol_新浪博客
2016-12-22 17:49:00在C++中使用虚基类的目的是可以在使用间接共同基类时只保留一份成员。因为一个基类可以在生成一个派生类时作为虚基类,当生成另一个类时可以不作为虚基类,这样就保证了派生类中只保留一份基类的成员。 #... -
虚函数和虚基类
2009-04-30 15:54:00如果一个类是作为基类使用,那么他的虚构函数一定要是虚的,即用virtual关键字(参数为零则为纯虚函数). 否则会有内存泄漏(很重要),因为当用基类的指针删除一个派生类的对象时,要调用派生类的析构函数.但是 其子类... -
php rabbitMQ,封装虚基类,直接使用
2020-12-17 09:52:42话不多说直接上代码。 publisher.php <?php require "rabbitmq.php"; class Publisher extends mqService { public function __construct($exchangeName,$queueName,$routeKey) { parent::__construct($... -
C/C++ 多继承{虚基类,虚继承,构造顺序,析构顺序}
2017-07-26 19:01:00如果同名变量或者函数出现不在同一层次,则底层派生隐藏外层比如继承基类的同名变量和函数,不会出现二义性,而如果出现在同一阶层,则会 出现二义性,解决办法:要么在同一阶层的底层(派生类)中重新定义可以解决,或者... -
C++虚函数,纯虚函数,抽象基类,虚基类(转)
2013-01-12 00:16:00虚函数:目的:为了引起晚绑定实现方法:在...这样的类称为纯抽象基类纯抽象基类,也称为纯虚类:目的:提供抽象的接口实现方法:包含纯虚函数特点:不能生成该类的对象虚基类:目的:为了消除二义性实现方法:vir... -
虚函数、纯虚函数、虚析构函数、虚函数指针、虚函数表、虚继承、虚基类
2020-07-29 10:07:20虚析构函数是为了解决基类的指针指向派生类对象,并用基类的指针删除派生类的对象。 虚析构函数使用 class Shape{ public: Shape(); //构造函数不能是虚函数 virtual double calcArea(); virtual ~Shape(); ... -
RTTI、虚函数和虚基类的开销分析及使用指导
2018-03-19 06:29:40“在正确的场合使用恰当的特性” 对称职的C++程序员来说是一个基本标准。想要做到这点,首先要了解语言中每个特性的实现方式及其开销。本文主要讨论相对于...但是应当看到,这些新机能在不降低,甚至(由于模板的...