博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ 虚拟继承问题
阅读量:2242 次
发布时间:2019-05-09

本文共 2215 字,大约阅读时间需要 7 分钟。

文章目录

前言

本篇文章主要描述虚拟继承中内存分布情况,当然,可能会不太完全正确,希望大家多多指正

为什么要有虚拟继承

我们看下面一种情景:

class A{
public: int a;};class B : public A{
public: int b;};class C : public A{
public : int C;};class D : public B, public C{
public: void func() {
}};

为了更加方便理解,用图表示:

在这里插入图片描述
如上图,那么就会出现问题:类D中的成员变量 int a,如果访问a,就会出现二义性问题,到底是B中的a,还是C中的A,并且会造成数据冗余问题。

其中,对于二义性问题,我们加访问限定即可。例如 C::a;但对于数据冗余问题却没有办法解决。

于是C++中就引入了虚拟继承

将代码改为:

class A{
public: int a;};class B : virtual public A{
public: int b;};class C : virtual public A{
public : int C;};class D : public B, public C{
public: void func() {
}};

如果,类中带有虚函数。内存结构会变为怎样??

class A{
public: A(int v = 100) :X(v) {
}; virtual void foo(void) {
} int X;};class B :virtual public A{
public: B(int v = 10) :Y(v), A(100) {
}; virtual void fooB(void) {
} int Y;};class C : virtual public A{
public: C(int v = 20) :Z(v), A(100) {
} virtual void fooC(void) {
} int Z;};class D : public B, public C{
D(int v = 40) :B(10), C(20), A(100), L(v) {
} virtual void fooD(void) {
} int L;};

在这里插入图片描述

对于类A,内存布局:
在这里插入图片描述
对于类B,内存布局:
在这里插入图片描述
对于类D,内存布局:
在这里插入图片描述

虚拟继承和普通继承的区别

class A{
public: virtual void funA();}; class B : public A{
public: virtual void funB();}
class A{
public: virtual void funA();}; class B : virtual public A{
public: virtual void funB();}

上述两种继承有什么区别??一种普通继承,一种虚拟继承

首先,我们知道,如果一个类中有虚函数,那么就会有一个虚表,有一个指针指向这个虚表。

对于A,内存布局如下:
在这里插入图片描述
对于普通继承,继承的虚函数和本有的虚函数共用同一个虚表
则普通继承 B布局如下:
在这里插入图片描述

但对于虚拟继承来说,不管是基类还是派生类都需要有一个指针来维护自己的虚表,并且还要有一个指针指向虚基表,其中存放偏移量

在这里插入图片描述

虚拟继承 sizeof() 问题

有了上面的基础,来看几道题:

//第一种情况class a         {
             virtual void func();};           class b:public virtual a{
             virtual void foo(); };           //第二种情况class a           {
                  virtual void func(); };              class b :public a     {
                  virtual void foo();  };                         //第三种情况class a         {
               virtual void func();   char x;       };            class b:public virtual a {
           virtual void foo();};            //第四种情况 class a {
   virtual void func()   char x; }; class b:public a {
   virtual void foo(); };

对于每种情况,分别计算 sizeof(a), sizeof(b)的大小

结果:
第一种:4,12
第二种:4,4
第三种:8,16
第四种:8,8

参照上述普通继承和虚拟继承的区别,就知道原因了。

转载地址:http://acwdb.baihongyu.com/

你可能感兴趣的文章
Java程序初始化的顺序
查看>>
Dubbo和Spring结合配置文件内容解析为bean的过程
查看>>
fastJson注解@JSONField使用的一个实例
查看>>
fastjson的@JSONField注解的一点问题
查看>>
fastjson使用(三) -- 序列化
查看>>
浅谈使用单元素的枚举类型实现单例模式
查看>>
Java 利用枚举实现单例模式
查看>>
Java 动态代理作用是什么?
查看>>
Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM) (清晰,浅显)
查看>>
三种线程安全的单例模式
查看>>
Spring AOP 和 动态代理技术
查看>>
从 volatile 说起,可见性和有序性是什么
查看>>
如何开始接手一个项目
查看>>
Netty 5用户指南
查看>>
Java实现简单的RPC框架
查看>>
一个用消息队列 的人,不知道为啥用 MQ,这就有点尴尬
查看>>
从零手写RPC
查看>>
高并发和多线程的关系
查看>>
Java并发与多线程
查看>>
对于多线程程序,单核cpu与多核cpu是怎么工作的
查看>>