虚继承

C++对象模型:单继承,多继承,虚继承,菱形虚继承,及其内存布局图

放肆的年华 提交于 2019-11-29 22:02:48
C++目前使用的对象模型: 此模型下, nonstatic数据成员被置于每一个类的对象中 ,而 static数据成员则被置于类对象之外 , static和nonstatic函数也都放在类对象之外(通过函数指针指向) ,而 对于virtual函数,则通过虚函数表+虚函数指针来支持 : 1)每个类生成一个表格,称为 虚表 (virtual table,简称vtbl),虚函数表中存在一堆指针,这些指针指向该类的每一个虚函数,虚表中的函数地址按照声明时的顺序排列 2)每个类对象都有一个 虚表指针 (简称vptr),由编译器为其生成,虚表指针的设定和重置皆由类的相关函数控制(构造函数,析构函数,赋值操作符),虚表指针vptr的位置由编译器决定,一般编译器把vptr放在一个类对象的最前端(也就是说对象的地址就是vptr的地址) 3)虚函数表的前面设置了一个指向type-info的指针,用以支持RTTI(Run Time Type Identification,运行时类型识别),RTTI是为支持多态生成的信息,包括对象的继承关系,对象本身的描述等,只有具有虚函数的对象才会生成 样例: class Base { public: Base(int i) :baseI(i){}; int getI(){ return baseI; } static void countI(){}; virtual

C++三大特性(继承、封装、多态)

穿精又带淫゛_ 提交于 2019-11-29 12:25:59
封装 就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。 继承 指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过 “继承”( Inheritance)和“组合”( Composition)来实现。继承概念的实现方式有三类:实现继承、接口继承和可视继承。 实现继承:是指直接使用基类的属性和方法而无需额外编码的能力; 接口继承:是指仅使用属性和方法的名称、但是子类必须提供实现的能力。 可视继承:可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。 多态 是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同

虚继承

。_饼干妹妹 提交于 2019-11-29 01:43:55
  尽管在派生列表中同一个基类只能出现一次,但实际上派生类可以多次继承同一个类。派生类可以通过它的两个直接基类分别继承同一个间接基类,也可以直接继承某个基类,然后通过另一个基类再一次间接继承该类。   举个例子,IO标准库的istream和ostream分别继承了一个共同的名为base_ios的抽象基类。该抽象基类负责保存流的缓冲内容并管理流的条件状态。iostream是另外一个类,它从istream和ostream直接继承而来,可以同时读写流的内容。因为istream和ostream都继承自base_ios,所以iostream继承了base_is两次,一次是通过istream,另一次是通过ostream。   在默认情况下,派生类中含有继承链上每个类对应的子部分。如果某个类在派生过程中出现了多次,则派生类中将包含该类的多个子对象。   这种默认的情况对某些形如iostream的类显然是行不通的。一个iostream对象肯定是希望在同一个缓冲区进行读写操作,也会要求条件状态能同时反映输入和输出操作的情况。假如在iostram对象中真的包含了base_ios的两份拷贝,则上述的共享行为就无法实现而了。    在C++语言中我们通过虚继承(virtual inheritance)的机制解决上述问题。虚继承的目的是令某个类做出声明,承诺愿意共享它的基类。其中,共享的基类子对象成为虚基类

虚继承和虚基类

南楼画角 提交于 2019-11-27 10:37:39
多继承(Multiple Inheri tan ce)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。尽管概念上非常简单,但是多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个。 多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如典型的是菱形继承,如下图所示: 图1:菱形继承 类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,一份来自 A-->B-->D 这条路径,另一份来自 A-->C-->D 这条路径。 在一个派生类中保留间接基类的多份同名成员,虽然可以在不同的成员变量中分别存放不同的数据,但大多数情况下这是多余的:因为保留多份成员变量不仅占用较多的存储空间,还容易产生命名冲突。假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A -->B-->D 这条路径,还是来自 A-->C-->D 这条路径。下面是菱形继承的具体实现: 复制纯文本复制 //间接基类Aclass A{protected: int m_a;}; //直接基类Bclass B: public A{protected: int m_b;}; //直接基类Cclass

C++继承、多态与虚表

拟墨画扇 提交于 2019-11-26 23:54:56
继承 继承的一般形式 子类继承父类,是全盘继承,将父类所有的东西都继承给子类,除了父类的生死,就是父类的构造和析构是不能继承的。 继承的访问权限从两方面看: 1.对象:对象只能直接访问类中公有方法和成员。 2.继承的子类 私有继承就终止了父类再往下继承的能力 c++默认继承为私有继承 像以下程序 class D :public B1 ,public B2,public B3 公有继承B1,B2,B3 class D :public B1,B2,B3; 公有继承B1,私有继承B2,B3 继承是按照继承的顺序,和构造函数的初始化顺序无关,看以下程序 如果,子类中有对象成员,构造顺序是:1.父类,2.对象成员,3.自己 如果父类中有虚基类,应该先构造虚基类 虚基类 虚基类主要解决菱形继承问题,有以下程序 继承模型为: 内存模型: 如果对父类的x进行赋值,如下程序,会引发错误,编译器会报错,因为继承了两份,会产生二义性 如果指定访问A1还是A2就不会报错 内存中只为A1的成员x赋值了 如果希望来自父类的x在子类中只有1份 那么就要用虚拟继承 对于虚继承来的基类,又叫做虚基类 现在对cc.c进行赋值 A1和A2对象中的x成员都变成100 如果不是虚拟机成A1和A2继承来的x各自是各自的空间 虚继承让子类只保持父类的一份成员拷贝,A1和A2的继承的成员的空间是一个