虚继承(c++常问问题九)

*什么是虚继承,使用虚继承来解决什么问题,什么是虚基类

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

#在现实生活中,一些新事物往往会拥有两个或者两个以上事物的属性,为了解决这个问题,C++引入了多重继承的概念,C++允许为一个派生类指定多个基类,这样的继承结构被称做多重继承

举个例子,交通工具类可以派生出汽车和船连个子类,但拥有汽车和船共同特性水陆两用汽车就必须继承来自汽车类与船类的共同属性。 

当一个派生类要使用多重继承的时候,必须在派生类名和冒号之后列出所有基类的类名,并用逗好分隔。

class Vehicle
{
    public:
        Vehicle(int weight = 0)
        {
            Vehicle::weight = weight;
            cout<<"载入Vehicle类构造函数"<<endl;
        }
        void SetWeight(int weight)
        {
            cout<<"重新设置重量"<<endl;
            Vehicle::weight = weight;
        }
        virtual void ShowMe() = 0;
    protected:
        int weight;
};
class Car:virtual public Vehicle//汽车,这里是虚拟继承
{
    public:
        Car(int weight=0,int aird=0):Vehicle(weight)
        {
            Car::aird = aird;
            cout<<"载入Car类构造函数"<<endl;
        }
        void ShowMe()
        {
            cout<<"我是汽车!"<<endl;
        }
    protected:
        int aird;
};  

class Boat:virtual public Vehicle//船,这里是虚拟继承
{
    public:
        Boat(int weight=0,float tonnage=0):Vehicle(weight)
        {
            Boat::tonnage = tonnage;
            cout<<"载入Boat类构造函数"<<endl;
        }
        void ShowMe()
        {
            cout<<"我是船!"<<endl;
        }
    protected:
        float tonnage;
};  

class AmphibianCar:public Car,public Boat//水陆两用汽车,多重继承的体现
{
    public:
        AmphibianCar(int weight,int aird,float tonnage)
        :Vehicle(weight),Car(weight,aird),Boat(weight,tonnage)
        //多重继承要注意调用基类构造函数
        {
            cout<<"载入AmphibianCar类构造函数"<<endl;
        }
        void ShowMe()
        {
            cout<<"我是水陆两用汽车!"<<endl;
        }
        void ShowMembers()
        {
            cout<<"重量:"<<weight<<"顿,"<<"空气排量:"<<aird<<"CC,"<<"排水量:"<<tonnage<<"顿"<<endl;
        }
};
int main()
{
    AmphibianCar a(4,200,1.35f);
    a.ShowMe();
    a.ShowMembers();
    a.SetWeight(3);
    a.ShowMembers();
    system("pause");
}

进阶部分:虚继承的内存占用下面看代码:

(演示了虚继承和非虚继承时的内存..看前请先恶补一下C++的字节对齐(我在c++常见问题的开篇中分析过))

//
class a1
{
	 virtual void func();
};

class b1 : public virtual a1
{
	virtual void foo();
};

//
class a2
{
	virtual void func();
};

class b2 : public a2
{
	virtual void foo();
};

//
class a3
{
	virtual void func();
	char a;
};

class b3 : public virtual a3
{
	virtual void foo();
};

//
class a4
{
	virtual void func();
	char a;
};

class b4 : public a4
{
	virtual void foo();
};

void main()
{
	cout<<sizeof(a1)<<","<<sizeof(b1)<<endl;
	cout<<sizeof(a2)<<","<<sizeof(b2)<<endl;
	cout<<sizeof(a3)<<","<<sizeof(b3)<<endl;
	cout<<sizeof(a4)<<","<<sizeof(b4)<<endl;

	system("pause");
}

第一种:4,12
第二种:4,4

第三种:8,16

第四种:8,8

想想这是为什么呢?

    因为每个存在虚函数的类都要有一个4字节的指针指向自己的虚函数表,所以每种情况的类a所占的字节数应该是没有什么问题的,那么类b的字节数怎么算呢?“第一种”和“第三种”情况采用的是虚继承,那么这时候就要有这样的一个指针vptr_b_a,这个指针叫虚类指针,也是四个字节;还要包括类a的字节数,所以类b的字节数就求出来了。而“第二种”和“第四种”情况则不包括vptr_b_a这个指针,这回应该木有问题了吧。

时间: 2024-12-06 01:42:24

虚继承(c++常问问题九)的相关文章

虚析构函数(c++常问问题五)

当子类析构需要调用父类的析构函数,基类的析构函数必须设置为虚析构函数 //基类 class base { base() { cout<<"base "; } virtual ~base() { cout<<"~base "; } } //派生类 class cat : public base { cat () { cout<<"cat "; } virtual ~cat () { cout<<&qu

新三板知识:客户最常问的22个问题及标准解答

新三板知识:客户最常问的22个问题及标准解答 新三板客户最常问的22个问题之标准解答 一.企业申请在新三板挂牌的条件有哪些 根据<全国中小企业股份转让系统业务规则>第2.1条的规定,股份公司申请挂牌应当符合下列条件: 1.依法设立且存续满两年.有限责任公司按原账面净资产值折股整体变更为股份有限公司,存续时间可以从有限责任公司成立之日起计算: 2.业务明确,具有持续经营能力: 3.公司治理机制健全,合法规范经营: 4.股权明晰,股票发行和转让行为合法合规: 5.主办券商推荐并持续督导: 6.全国

C++中的虚继承 &amp; 重载隐藏覆盖的讨论

虚继承这个东西用的真不多.估计也就是面试的时候会用到吧.. 可以看这篇文章:<关于C++中的虚拟继承的一些总结> 虚拟基类是为解决多重继承而出现的. 如:类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

iPhone开发常问的十个问题

iPhone开发常问的十个问题 前言 今天去stackoverflow.com上看了一下iPhone标签下排名最高的10个问题,将它们整理出来,希望这些常见问题能帮到一些iPhone开发的初学者.本来想把答案也翻译过来的,后来发现答案资料通常都比较复杂,翻译起来太麻烦.所以大家还是看英文的答案吧,我只顺带用中文总结一下答案. 问题一: 有哪些iPhone开发和Objective-C的入门资料 这个确实是最常问的问题了.对于我个人来说,入门时所看的资料主要是<From C++ to Objecti

C++继承详解之三——菱形继承+虚继承内存对象模型详解vbptr(1)

在我个人学习继承的过程中,在网上查阅了许多资料,这些资料中有关菱形继承的知识都是加了虚函数的,也就是涉及了多态的问题,而我在那个时候并没有学习到多态这一块,所以看很多资料都是云里雾里的,那么这篇文章我想以我自己学习过程中的经验,由简到较难的先分析以下菱形继承,让初学者先对这个问题有一点概念,在后面会由浅入深的继续剖析. 本篇文章不会涉及到多态也就是虚函数的菱形继承,在后面的文章更新中,我会慢慢把这些内容都加进去. 菱形继承(也叫钻石继承)是下面的这种情况: 对应代码如下: #include <i

多重虚继承下的对象内存布局

<深入C++对象模型>绝对是一本值得深读的一本书,书里多次出现一句话,“一切常规遇见虚继承,都将失效”.这是一个有趣的问题,因为C++标准容忍对象布局的实现有较大的自由,出现了各编译器厂商实现的方式不同. 今天谈谈visual studio2013多重虚继承下对象布局.有错不要客气,不要吝啬你的留言,请直接开喷. class y和class z都是从class x虚继承来的子类(也叫派生类),class A是class y和class z的多重继承子类.为了简化问题,下面的data membe

销售人员常犯的九项错误

1.忘了自己的微笑 2.争辩 3.离客户太近,过于热情 4.轻易地作出了让步 5.忽略了客户正真的需求 6.轻易地给客户下结论 7.忽略了老客户 8.过于专业 9.轻易地承诺 1.忘了自己的微笑 销售人员走南闯北,有时是刮风下雨.有时天寒地冻.有时烈日炎炎,还有一些人为的因素,不可避免地会带有一些情绪,与客户见面的时候,忘了自己的微笑.心里学上讲,人与人之间的交往,前10秒钟最关键,10秒中决定对方以何种态度跟你接触,微笑是上天赐给我们重要的肢体语言,如果一开始你的肢体语言给对方的印象是:"其实

java面试常问的几个问题

1,作用域public,protected,private,以及不写时的区别 2,ArrayList和Vector的区别,HashMap和Hashtable的区别 3,char型变量能不能定义为一个中文?为什么? 4,多线程有几种表示方法,都是什么?同步有几种实现方法,都是什么? 5,继承时候类的执行顺序问题,一般都是选择题,问你将会打印出什么? 6,内部类的实现方式? 7,垃圾回收机制,如何优化程序? 8,float型float f=3.4是否正确? Jsp方面 1,jsp有哪些内置对象?作用

C++ 虚函数和虚继承浅析

本文针对C++里的虚函数,虚继承表现和原理进行一些简单分析,有希望对大家学习C++有所帮助.下面都是以VC2008编译器对这两种机制内部实现为例. 虚函数 以下是百度百科对于虚函数的解释: 定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数[1] 语法:virtual 函数返回类型 函数名(参数表) { 函数体 } 用途:实现多态性,通过指向派生类的基类指针,访问派生类中同名覆盖成员函数 函数声明和定义和普通的类成员函数一样,只是在返回值之前加入了关键字"vir