有关C++虚拟继承的简单理解

最近在看《深度探索C++对象模型》这本书的时候,里面第一章提到了虚拟继承,有这么一句话说:“在虚拟继承的情况下,base
class不管在继承串链中被派生多少次,永远只会存在一个实体。”一开始我理解错了,以为这个继承类图体系里面全局只有一个base
class对象,后来查了些资料才知道意思是一个子类中只包含一个bass class对象。

很多东西要有对比才能认识得更深刻,我们这里对比下虚拟继承和普通继承的子类对象的区别,也从而让我们更好地理解文章开头提到的书里的那句话。

虚拟继承样例:


class CTestBase
{
public:
int base_data_;
};

class CTestSubject1:virtual class CTestBase
{
public:
int subone_data_;
};

class CTestSubject2:virtual class CTestBase
{
public:
int subtwo_data_;
};

class CTestDiamond:public CTestSubject1,public CTestSubject2
{
public:
int dia_data_;
};

int main()
{
CTestDiamond dia;
dia.base_data_ = 1;
}

上面当中dia.base_data_能够被赋值,再看普通继承的例子。

普通继承样例:


 1 class CTestBase
2 {
3 public:
4 int base_data_;
5 };
6
7 class CTestSubject1:public CTestBase
8 {
9 public:
10 int subone_data_;
11 };
12
13 class CTestSubject2:public CTestBase
14 {
15 public:
16 int subtwo_data_;
17 };
18
19 class CTestDiamond:public CTestSubject1,public CTestSubject2
20 {
21 public:
22 int dia_data_;
23 }
24
25 int main()
26 {
27 CTestDiamond dia;
28 dia.base_data_ =1;
29 }

这时候就出问题了,同样的继承结构,但是只不过没有了虚拟继承,我们对dia.base_data_的赋值就不能通过编译了,这是因为没有了虚拟继承,我们的dia对象中有2个base_data_,一个是从CTestSubject1中继承来的,另一个是从CTestSubject2中继承来的。这样一来编译器就不知道具体要给哪个base_data_赋值了,而当我们用虚拟继承时,对象dia中只有一个base_data_,所以显而易见编译器就知道该怎么赋值。这就是那句话的意思,不管继承多少次,永远只会存在一个虚基类的实体。

那我们该怎么在普通继承中对多个base_data_赋值呢?

我们只需要dia.CTestSubject1::base_data_ =
1,这样编译器就知道我们是想给CTestSubject1中的base_data_赋值了。CTestSubject2里面的base_data_也同理。

总结:

通过上面的2个例子,我们很容易看出虚拟继承和普通继承的区别,我觉得学习语言不需要去纠结语法,而应该去理解各种语法用法之间的区别,具体怎么用,只有结合实际中的编程场景,通过分析选择最合适的方式来使用,相信存在即是道理。

当然上面只是从表面来分析虚拟继承和普通继承,更深层次地可以从对象模型和内存布局去理解。

有关C++虚拟继承的简单理解

时间: 2024-10-13 16:46:55

有关C++虚拟继承的简单理解的相关文章

JS继承(简单理解版)

童鞋们,我们今天聊聊js的继承,关于继承,平时开发基本用不到,但是面试没有不考的,我就想问,这是人干的事吗? 好吧,迫于社会主义核心价值观,我们今天就来简单说一说js的继承,谁让它是面向对象编程很重要的一个方面呢 首先一句定义,什么是继承: A对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法. 常见的集成方式有六种,我们今天依次简单的说一下,现在让我们把这六种方式分一下类,大致上可分为三类 第一类:普通类 这类继承方法有个特性,就是简单,容易实现,一共两种: 1.原型链继承 关键点

public/protect/private和公有继承/保护继承/私有继承的简单理解

一.先来看一下没有继承的情况 类中的变量访问: (1)类内访问方式:通过public成员函数访问 (2)类外访问方式:直接访问 表 1 class A { public: int a; protected: int b; private: int c; public: int getAll(){ return a + b + c; } }; int main() { A testA; //类外访问方式 testA.a; testA.b; testA.c; //类内访问方式 testA.getAl

php类的封装、继承和多态的简单理解

.面象对向的三大特点:封装性.继承性.多态性 首先简单理解一下抽象: 我们在前面定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象 一.封装性  封装就是把抽取出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有被授权的操作(方法)才能对数据进行操作.  php提供了三种访问控制修饰符  public 表示全局,本类内部,类外部,子类都可以访问  protected 表示受保护的,只有本类或子类可以访问  pr

深入理解虚表之非虚拟继承及虚拟继承

非虚拟继承 [带虚函数的类] class Base { public: virtual void FunTest1() { cout<<"Base::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base::FunTest2()"<<endl; } int _data1; }; int main() { Base b; b._data1 = 0x01; re

C++ 继承、多继承、虚拟继承对象模型

C++面向对象语言一大难点是继承,但又是不得不掌握的.简单的继承是很容易理解的,但是当涉及到多继承,设计到虚函数的继承,特别是涉及到虚继承时,问题就会变得复杂.下面的内容来自参考资料中的三篇文章.C++的继承学习中,最主要是要掌握派生类的对象模型,基类和派生类指针之间的向上向下类型转换,当继承中的出现虚函数成员函数的访问(多态),虚继承是如何通过引入虚基表解决"菱形继承"中存在多份公共基类的问题. 一.简单的对象模型 1.定义 class MyClass { public: int v

对Javascript的原型,原型链和继承的个人理解

继承是OO语言中一个最为人津津乐道的概念,也是初接触Javascript的初学者难理解的概念=.=继承主要分为两种:一种是接口继承,另一种是实现继承.而在ECMAScript中只支持实现继承,所以我们今天来讨论讨论实现继承.实现继承就是继承实际的方法,主要依靠原型链来实现.讲到这里我们就需要讨论讨论什么是原型链. 1.什么是原型 要理解原型链我们首先要知道什么是原型.我们知道每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象包含所有实例共享的属性和方法.所以我个人

对数据类型封装和数据抽象的简单理解

请特别关注程序设计技术,而不是各种语言特征. --<C++程序设计语言> Bjarne Stroustrup 本文是<C++程序设计语言>(Bjarne Stroustrup )的第二章的读书笔记,例子来源于这本书的第二章. 在程序设计之中,我们倾向于将数据结构(也可以说是数据类型)以及一组对其操作的相关过程组织在一起,在逻辑上可以称将其为模块.此时程序分为一些模块,模块包括一组对数据的操作,数据隐藏于模块之中.以下以栈的设计为例,使用C和C++进行设计,简单理解模块化设计中的数据

大话设计模式总结(28种设计模式定义+简单理解)

大话设计模式这本书写的非常有创意,非常适合我这种新手.用了大约两个星期的时间看完了这本书,代码全部都敲了一遍,虽然没有一点基础,但是还是领略到了面向对象的威力.看完之后再也不想使用面向过程的语言了,比如VB,想当初我也是VB狂热者,但是现在我几乎不想再使用了.现在只想着写点什么用上它几种设计模式. 可能是第一次接触这些东西,有些感觉看懂了,但是很难应用到实际编程中:有些感觉没看懂,但是还能说出那么点东西来.听七期学长说他们当初看了两遍,要求能背着写出代码,不知道这次我们八期要求怎么这么低,我只看

深入探索C++对象象模型--拷贝构造函数 &amp;&amp;多重继承 虚拟继承 内存分布

拷贝构造函数 如果没有定义拷贝构造函数,那么编译器会自动生成一个拷贝构造函数,但是这个拷贝构造函数是有一定限度的. 一般来说这个拷贝构造函数是按照位直接拷贝的,但是在有些情况下这种初始化是有问题的,在特殊的四种情况下是有问题的,在有问题的情况下,可以举例说明. 如果一个有多态性质的对象,子类赋值给父类,调用了拷贝构造函数,这个时候就需要给父类的虚拟函数表重新分配,使得虚拟函数表和子类不是同一个,这样bitwist就不能有效 对于在函数参数中调用拷贝构造函数,参数是实参的一根拷贝,对于函数的返回值