首页
学习
活动
专区
圈层
工具
发布
    • 综合排序
    • 最热优先
    • 最新优先
    时间不限
  • 来自专栏码云1024

    c++ 继承

    前提概念: 多重继承:比如类a继承类b,类b继承类c,这类关系称为多重继承继承:比如类a继承类b和类c,这类关系称为多继承 典型问题: 例如: 农民类和工人类继承自人类,农民工类继承自农民类和工人类 这种菱形的继承将为带来农民工类中将有两份人类中的成员,导致数据冗余。 解决方案——继承: 关键字:virtual class people; class farmer:virtual public people; class worker:virtual public

    81570发布于 2018-05-10
  • 来自专栏程序员

    C++继承

    如果一个类从多个类继承而来,而这些类有公共基类。那么在多该基类中定义的成员访问时会出现二义性。C++设计继承来解决这个问题。继承的本质就是子类引用父类的内存空间,而不创建自己的内存空间。 这样既解决了多重继承可能引发的二义性问题,也使得内存得以释放。 在继承过程中的基类被叫做:基类 那么实际上,继承的本质就是使用一个指向基类的指针,这样就无论你怎么继承,就只有一份基类内存空间。 C++使用关键字virtual来进行继承。 { }; int main() { Last L; L.a; return 0; } 通过继承,这样MyClass类的内存空间只有一份。 这种情况下,继承也无法帮到我们。我们只能使用 c.A::a; c.B::a; 来明确对类成员的调用,从而避免二义性的产生。

    95620发布于 2020-04-08
  • 来自专栏C++教程

    【Example】C++ 基类与继承 (菱形继承问题)

    C++ 是支持多继承的语言,但是实际项目开发中非必要请避免使用多继承以降低代码逻辑的复杂性。 当然 C++继承的特性带来一些问题即菱形继承。 ? Byte 、Expert、Frog 三个类,但是 Frog 类不是以继承的方式继承 Base 的。 同时,在继承机制当中,基类是由最终的派生类进行初始化的,本身达成了一种 “间接继承” 的关系。 也就意味着最终的派生类在构造函数初始化中,要在初始化表中调用基类的构造函数进行初始化。 :【Example】C++ 基类与继承 (菱形继承问题) 继承时,子类的内存结构当中不包含父类。 【Example】C++ 接口(抽象类)概念讲解及例子演示 【Example】C++ 基类与继承 (菱形继承问题) 【Example】C++ Template (模板)概念讲解及编译避坑 【Example

    1.4K30编辑于 2022-04-28
  • 来自专栏游戏开发司机

    C++:53---菱形继承继承

    一、菱形继承 在介绍继承之前介绍一下菱形继承 概念:A作为基类,B和C都继承与A。 继承也可以解决这个问题 ? ) 共享的基类对象成为“基类” 说明:继承不会影响派生类本身,只是对基类进行的说明 通过在继承列表中使用virtual关键字来说明,virtual与继承说明符(public、protected、private {}; 三、继承中的类型转换 继承中也可以将派生类抓换为基类,用基类的指针/引用指向于派生类 菱形继承中的类型转换 菱形继承中会发生错误,不能将派生类转换为基类 原理是差不多的,就是因为派生类中拥有多份基类的实体 解决二义性最好的办法就是在派生类为成员自定义新的实例 五、继承的构造函数 继承中的构造函数与普通继承的构造函数不一样: 普通继承:派生类可以不为间接基类(基类的基类)进行构造函数的调用 继承:不论派生类属于哪一层

    1.3K40发布于 2021-02-03
  • 来自专栏游戏开发司机

    C++:14---继承函数,多态

    此种菱形继承多存储了两倍的A的内存段,下面将介绍基类 ? 二、基类(virtual) 1.概念:也称继承、菱形继承。 用于多级混合继承时,保留一个基类 2.构造顺序 先构造基类,如果有多个基类,按声明(从左至右)依次构造 再构造基类,如果有多个基类,按声明(从左至右)依次构造 如果有子对象,再构造子对像,如果有多个子对象 B,于是去构造B,构造B的时候,发现继承基类A,于是构造基类A,接着构造B。 再接着构造C,发现C继承基类A,但发现基类A已经被B构造过了,所以不再构造A,直接构造C。 地址解析: B和C中都保存了A的值,但是在D继承B和C的时候,只保存了一份A,且放在最后 在D继承的B和C内存段中分别有一个函数指针放在最前方 二、函数表 1.概念:是一块连续的内存,所有函数的首地址都存放在函数表中

    97910发布于 2021-02-03
  • C++高级主题】继承

    C++ 面向对象编程中,多重继承(Multiple Inheritance)允许一个类继承多个基类的特性,这在设计复杂系统(如 “可序列化”+“可绘制” 的图形组件)时非常有用。 2.1 继承的声明方式 在 C++ 中,通过 virtual 关键字声明继承,确保公共基类在派生类中仅存一份实例。 六、继承的常见误区与最佳实践 6.1 误区一:继承可以解决所有多重继承问题 继承仅解决菱形继承的公共基类二义性,无法解决非菱形结构的成员冲突(如两个无关基类的同名成员)。 七、总结 继承C++ 为解决菱形继承问题设计的关键机制,通过 virtual 关键字声明,确保公共基类在最终派生类中仅存一份实例,消除二义性并减少数据冗余。 尽管继承在复杂系统中不可替代,现代 C++ 设计更倾向于通过 组合模式(Composition)和接口继承(纯类)减少多重继承的使用。

    20110编辑于 2026-01-21
  • 来自专栏开发与安全

    从零开始学C++继承(三):多重继承继承基类

    只能通过 sofaBed.Bed::weight_ = 10; 访问,但实际上一个sofaBed理应只有一个weight_,下面通过基类和继承可以解决这个问题。 二、继承基类 当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性,可以采用基类来解决。 基类的引入 用于有共同基类的场合 声明 以virtual修饰说明基类 例:class B1:virtual public BB 作用 主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题 2、在整个继承结构中,直接或间接继承基类的所有派生类,都必须在构造函数的成员初始化表中给出对基类的构造函数的调用。如果未列出,则表示调用该基类的默认构造函数。 参考: C++ primer 第四版 Effective C++ 3rd C++编程规范

    1.4K00发布于 2017-12-28
  • 来自专栏小小黑的游戏开发之路

    菱形继承问题及解决方法—继承基类(C++

    菱形继承 菱形继承的概念 两个派生类继承同一个基类,又有某个类同时继承着这两个派生类 菱形继承典型案例 这种继承带来的问题主要有两方面: 羊和驼都继承了动物的类成员,当羊驼想要使用时,会产生二义性 二是通过继承的方式,使羊驼仅继承一份数据。 m_Age,通过限定作用域的方式无法彻底解决这个问题,这个时候就要使用继承 继承基类 具体实现为在羊类和驼类的继承前加上virtual关键词,Animal类称为基类 代码如下: #include Animal{}; //继承 class Tuo :virtual public Animal{}; //继承 class SheepTuo :public Sheep, public Tuo{} 可以看出羊类和驼类中的数据只是一个基类指针,并未继承具体的数据,这个基类指针指向各自的基类表,而基类表中存在一个偏移量,通过这个偏移量再加上首地址可以找到基类中的数据,所以实际上羊驼只继承了一份数据

    1.7K40编辑于 2022-10-27
  • 来自专栏游戏开发司机

    C++:13---继承(单一继承、多重继承、多级继承、菱形继承继承

    缺点的解决: 数据冗余:通过下面“继承”技术来解决(见下) 访问不明确(二义性):通过作用域访问符::来明确调用。 继承也可以解决这个问题 ? std::cout << getMa();*/ //正确,通过B访问getMa() std::cout << B::getMa(); } private: int m_d; }; 八、继承 继承的作用:为了保证公共继承对象在创建时只保存一分实例 继承解决了菱形继承的两个问题: 数据冗余:顶级基类在整个体系中只保存了一份实例 访问不明确(二义性):可以不通过作用域访问符::来调用(原理就是因为顶级基类在整个体系中只保存了一份实例 ) 继承不常用,也不建议使用 class A { public: A(int a) :m_a(a) {} int getMa() { return m_a; } private: int m_a; }

    4.8K30发布于 2021-02-03
  • 来自专栏韩曙亮的移动开发专栏

    C++继承 ⑫ ( 继承的二义性 | virtual 继承 )

    40; // 控制台暂停 , 按任意键继续向后执行 system("pause"); return 0; } 执行结果 : 二、virtual 继承 1、继承引入 在多继承中 , 如果一个类继承了多个含有相同基类的派生类 , 就会产生菱形继承结构 ; 这种情况下 , 可能会出现多个不同的基类实例 , 导致重复定义和二义性 ; 为了应对上述 继承的二义性 问题 , C++ 语言 使用 " 继承 " 解决 继承中的 二义性问题 ; C++ 中的 " 继承 " 是一种解决 多继承 带来的 菱形问题(diamond problem)的技术 ; 继承的目的是 确保每个基类只被继承一次 , 从而避免 重复定义 和 二义性等问题 ; 继承 通过在 派生类 中使用关键字 virtual 来指示基类应该被继承 , 继承确保了每个基类只被继承一次 , 从而避免了重复定义和二义性 ; 在 C++ 中,使用继承的语法是在基类列表中使用 virtual 关键字 ; 2、继承语法 继承语法 : 在 继承的 访问限定符 之前 , 添加 virtual 关键字 , 将该继承行为定义为 " 继承 " ; class 子类类名 : virtual

    45720编辑于 2023-10-27
  • 来自专栏cpp加油站

    c++头脑风暴-多态、继承、多重继承内存布局

    总结一下:c++继承时的多态一般指的运行时多态,使用基类指针或者引用指向一个派生类对象,在非虚继承的情况下,派生类直接继承基类的表指针,然后使用派生类的函数去覆盖基类的函数,这样派生类对象通过表指针访问到的函数就是派生类的函数了 三、继承 如果仔细看的话,可以发现我先前多次强调了非虚继承,这是因为在没有函数的时候是不是继承影响不大,但存在函数的时候继承和非虚继承是不一样的,如下: #include <iostream> 这说明继承不只是实现了派生类自己的表指针,还重新生成了属于它自己的函数表,但这样一来,等于继承就比非虚继承多了很多开销,所以大多数情况还是不要使用继承吧。 有人会说,上面不是说继承会重新生成表指针吗,但这里是类B继承类A,但是类D继承的时候是非虚继承,所以类D并不会重新生成表指针,但此处类B和类C应该重新生产表指针,gdb查看却没有,我一开始也很疑惑 ,基类的表指针和成员变量在后; 多重继承时最好使用继承,否则不只是会产生令人头疼的二义性问题,还会多一份基类的拷贝,使用继承以后,大家共享基类,既节约了空间,又避免了二义性问题。

    97520发布于 2021-06-29
  • 来自专栏C/C++基础

    C++虚拟继承基类

    1.多重继承带来的问题 C++虚拟继承一般发生在多重继承的情况下。C++允许一个类有多个父类,这样就形成多重继承。 (2)被虚拟继承的基类,叫做基类。基类实际指的是继承的方式,而非一个基类,是动词,而非名词。 (3)为了实现虚拟继承,派生类对象的大小会增加4。 这个增加的4个字节,是因为当虚拟继承时,无论是单继承还是多继承,派生类需要有一个基类表来记录继承关系,所以此时子类需要多一个基类表指针,而且只需要一个即可。 (4)虚拟继承中,基类对象是由最远派生类的构造函数通过调用基类的构造函数进行初始化的,派生类的构造函数的成员初始化列表中必须列出对基类构造函数的调用;如果未列出,则表示使用该基类的缺省构造函数。 ---- 参考文献 [1]陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008[8.3(P276-P280)]

    1.2K20发布于 2018-08-03
  • 来自专栏用户9199536的专栏

    C++|对象模型|多继承机制实现

    本文参考深度探索C++对象模型 ---- 我们常常使用基类指针指向派生类对象,那么,为什么基类指针能够如此轻松的调用派生类的方法呢?在多继承的情况下,this指针必须经过调整,才能正确地找到表。 下文为你介绍多继承模型下的指针偏移机制 ---- 指针偏移存在机制: 设一个多继承的类内存布局如下,单词代表对象首地址。 调用时:基->派生 指向第二个基类的指针,调用派生类的函数。 clone,Derived重写了clone,那么需要向后调整Base1长度以正确指向Derived object ---- 使用派生类指针指向派生类 调用时:派生->基 指向派生类的指针,调用第二个基类继承来的函数 根据调用的指针类别判断是否需要调用有调整的函数 函数较大时,产生多重进入点,函数体分为(1)调整this (2)执行自定义函数码,根据是否需要调整,通过thunks跳转至对应的进入点 address points: 函数期待获得的是引入函数的类对象的地址

    69520发布于 2021-11-22
  • 来自专栏韩曙亮的移动开发专栏

    C++继承 ⑬ ( 继承原理 | 继承解决继承二义性问题 | 二义性产生的原因分析 )

    一、继承原理 1、继承解决继承二义性问题 继承的二义性 : 如果 一个 子类 ( 派生类 ) 继承多个 父类 ( 基类 ) , 这些父类 都继承了 相同的父类 , 那么 子类 访问 父类的父类 中的成员 , 就会产生 二义性 ; 报错 : error C2385: 对“x”的访问不明确 ; 使用 " 继承 " 可以解决上述问题 , 子类 继承父类时 , 在 访问限定符 之前使用 virtual 关键字 , 即可将 普通继承 改为 继承 ; 下面的代码中 A 是父类 ; B 类 和 C 类 继承 A 类 , 这样当 某个类 同时 多继承 B 类 和 C 类时 , 访问 A 类中的成员时 , 不会出现 二义性 ; 由于 B 和 C 继承 A , D 类访问 A 中的成员 , 不会产生二义性 ; class A { public: int x; }; // 子类 B 继承了父类 A 的 x 成员 对象调用 , 一次由 C 对象调用 ; 此时 D 对象中就包含了 两个 A 类的 子对象 ; 当 访问 A 类的成员时 , 不知道访问哪个 A 类的成员 , 就出现了二义性 ; 3、继承原理 使用 继承

    60520编辑于 2023-10-27
  • 来自专栏技术点滴

    函数与继承寻踪

    函数与继承寻踪 封装、继承、多态是面向对象语言的三大特性,熟悉C++的人对此应该不会有太多异议。 继承机制解决了对象复用的问题,然而多重继承又会产生成员冲突的问题,继承在我看来更像是一种“不得已”的解决方案。 virtual在C++中最大的功能就是声明函数和基类,有了这种机制,C++对象的机制究竟发生了怎样的变化,让我们一起探寻之。 为了查看对象的结构模型,我们需要在编译器配置时做一些初始化。 图4 MyClassC对象模型 基类表每项记录了被继承基类子对象相对于基类表指针的偏移量。 尤其是在多重、虚拟继承下的复杂结构。通过这些真实的例子,使得我们认清C++内class的本质,以此指导我们更好的书写我们的程序。

    1.1K90发布于 2018-02-05
  • 来自专栏bit哲学院

    c++继承 基类 派生类 函数

    参考链接: C++继承 继承    类和类的关系有组合、继承和代理。继承的本质就是代码复用。子类继承父类中的一些东西,父类也称为基类,子类也称为派生类。派生类继承了基类除构造函数以外的所有成员。  继承的方式    继承方式有public(公有继承)、private(私有继承)和protected(保护继承)。 基类中不同访问限定符下(public、protected、private)的成员以不同的继承方式继承,在派生类中的访问限定也不同,具体如下:  基类的布局优先于派生类  #include<iostream 基类中含有函数,那么基类布局中存在一个函数指针,指向函数表;且其派生类中与其同名同参的函数不需要加virtual也是函数。 vfptr指针指向的vftable(函数表)中,&Base_meta中存放了RTTI信息(运行时类型信息),也就是class Base,0表示偏移,&Base::Show表示函数的入口地址。

    1.7K20发布于 2021-02-03
  • 来自专栏歪歪梯Club

    C++继承函数、RTTI、友元类、异常处理

    继承 前面讲到c++继承是子类在继承时声明继承的权限,之前描述有点不够准确。以下时书中提及的能继承的成员。 ? 当使用protected继承时,父类的所有public成员在当前子类中会变为protected。==。 函数 c++中,被定义为函数的成员,能被子类重写,函数是用virtual修饰的函数。 因为引用类型是父类型,在调用普通方法时,仍是父类方法,只有调用方法时,使用了真正的子类方法。而指针类型也是与引用类型类似。 析构函数与继承 c++中子类析构函数结束会自动调用父类析构函数。 在c++中有对应的纯函数,具备纯函数的类不能进行实例化,纯函数指将函数赋值为0的函数,如 class A{ virtual pureVirtualFunction() = 0; } 类的提前声明 代码示例 try{ throw "I am string"; }catch(const char * msg){ //code } final 与java类似,c++也有final,通过在类名后面或者函数后面加上

    1.1K10发布于 2020-08-17
  • 来自专栏c/c++&&linux

    c++】多态&&函数&&抽象类&&继承中的函数表详解

    Person* p2 = new Student; delete p1; delete p2; return 0; } 2.4 C++11 override 和 final 从上面可以看出,C+ 函数的继承是一种接口继承,派生类继承的是基类函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成函数 4. 重写是语法的叫法,覆盖是原理层的叫法 另外Func2继承下来后是函数,所以放进了表,Func3也继承下来了,但是不是函数,所以不会放进函数表本质是一个存函数指针的指针数组,一般情况这个数组最后面放了一个 单继承和多继承关系中的函数表 5.1 单继承中的函数表 class Base { public: virtual void func1() { cout << "Base::func1" << 所以菱形继承、菱形虚拟继承我们的表我们就不看了,一般我们也不需要研究清楚,因为实际中很少用 C++ 函数表解析 | 酷 壳 - CoolShell C++ 对象的内存布局 | 酷 壳 - CoolShell

    83110编辑于 2024-06-04
  • 来自专栏我命由我不由天

    C++继承、多继承情况下的函数表分析

    C++的三大特性之一的多态是基于函数实现的,而大部分编译器是采用函数表来实现函数,函数表(VTAB)存在于可执行文件的只读数据段中,指向VTAB的表指针(VPTR)是包含在类的每一个实例当中。 《深度探索C++对象模型》 一、单继承 1 #include<iostream> 2 #include <stdio.h> 3 using namespace std; 4 class A { vptr2[1](); 34 35 return 0; 36 } 运行结果: B1::bar D::foo D::bar \\\\\\ D::bar B2::foo 结论: 多重继承会有多个函数表 ,几重继承,就会有几个函数表。 再简单总结一下 覆盖 隐藏 重载 的区别: 覆盖 是C++函数的实现原理,基类的函数被子类重写,要求函数参数列表相同; 隐藏 是C++的名字解析过程,分两种情况,基类函数有virtual,参数列表不同

    3K10发布于 2019-08-02
  • C++】菱形继承为何会引发二义性?继承如何破解?

    解决冗余的办法:继承! 1.3继承 有了多继承就可能有菱形继承,而菱形继承又存在二义性和数据冗余等问题。所以C++就引入了继承来解决数据的冗余问题。 1.3.1为什么通过继承可以将Person部分成员提取出来? 菱形虚拟继承的原理: 继承通过共享基类实例实现成员提取。 当使用继承时,派生类会包含一个指向共享基类实例的指针(基类指针),而非直接嵌入基类成员。这使得不同路径继承基类在最终派生类中指向同一内存地址。 每个包含基类的派生类都会生成基类表,记录基类相对于该派生类起始地址的偏移量。这使得无论通过哪条继承路径访问,都能定位到同一个基类实例。 基类指针或引用 编译器会为继承的类生成额外的信息(如基类表或偏移量),用于在运行时定位共享基类子对象。这通常通过基类指针(vptr)或间接寻址实现。

    23110编辑于 2025-12-23
领券