首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

C++多重继承+虚函数( - 模糊)=奇怪的行为(也是函数指针)

C++多重继承+虚函数( - 模糊)=奇怪的行为(也是函数指针)

在C++中,多重继承是指一个类可以从多个基类继承属性和方法。虚函数是一种在基类中声明的函数,可以在派生类中进行重写,实现多态性。函数指针是指向函数的指针变量。

当多重继承和虚函数结合时,可能会出现一些奇怪的行为。这是因为多重继承会引入多个基类的成员和虚函数表,而虚函数表是用于实现动态绑定的机制。当存在多个基类的虚函数表时,编译器需要进行一些复杂的处理来解决函数调用的问题,这可能导致一些意外的结果。

具体来说,当一个类通过多重继承继承了多个基类的虚函数时,如果这些基类中存在同名的虚函数,编译器需要进行函数指针的调整,以保证正确地调用相应的虚函数。这个调整过程可能会导致一些奇怪的行为,比如函数调用的结果与预期不符。

为了避免这种奇怪的行为,可以采取以下几种方法:

  1. 尽量避免多重继承,尤其是在涉及到虚函数的情况下。如果可能的话,可以通过其他方式来实现类之间的关系,比如组合。
  2. 如果必须使用多重继承,可以通过虚拟继承来解决冲突。虚拟继承可以确保只有一个实例的基类子对象被创建,从而避免了函数指针调整的问题。
  3. 在设计和实现过程中,尽量避免同名的虚函数,以减少潜在的冲突。

总之,C++中的多重继承和虚函数结合可能会导致一些奇怪的行为,需要在设计和实现时注意避免潜在的冲突。对于开发者来说,理解多重继承、虚函数和函数指针的工作原理是非常重要的,以便能够正确地处理和解决相关的问题。

腾讯云相关产品和产品介绍链接地址:

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

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

那么大家想想为什么有人扫红包又大又新鲜8块、10块...,而有人扫红包都是1毛,5 毛.... 其实这背后也是一个多态行为。...,那么就你扫码金额 = random()%1;总结一下:同样是扫码动作,不同用户扫得到不一样红包,这也是一种多态行为。...重写是语法叫法,覆盖是原理层叫法 另外Func2继承下来后是函数,所以放进了表,Func3也继承下来了,但是不是函数,所以不会放进函数表本质是一个存函数指针指针数组,一般情况这个数组最后面放了一个...表中 找到函数是Student::BuyTicket 这样就实现出了不同对象去完成同一行为时,展现出不同形态 反过来思考我们要达到多态,有两个条件,一个是函数覆盖,一个是对象指针或引用调用函数...所以菱形继承、菱形虚拟继承我们表我们就不看了,一般我们也不需要研究清楚,因为实际中很少用 C++ 函数表解析 | 酷 壳 - CoolShell C++ 对象内存布局 | 酷 壳 - CoolShell

33710

C++继承函数、纯函数、普通函数,三者区别

https://blog.csdn.net/jxq0816/article/details/82625408 1.函数(impure virtual)   C++函数主要作用是“运行时多态...; } }; 2.纯函数(pure virtual)        C++中包含纯函数类,被称为是“抽象类”。...抽象类不能使用new出对象,只有实现了这个纯函数子类才能new出对象。   C++函数更像是“只提供申明,没有实现”,是对子类约束,是“接口继承”。   ...C++函数也是一种“运行时多态”。   ...普通函数是父类为子类提供“强制实现”。   因此,在继承关系中,子类不应该重写父类普通函数,因为函数调用至于类对象字面值有关。

1.3K30

C++】多态 ⑧ ( 验证指向 函数 vptr 指针 | 对比定义了函数类和没有定义函数大小 )

vptr 指针 是否存在 1、函数表与 vptr 指针由来 " 函数表 " 由 C++ 编译器 负责 创建 与 维护 , 被 virtual 关键字 修饰 函数 , 会自动 被 C++ 编译器...存储到 " 函数表 " 中 ; 函数表 创建 : 在 类 中使用 virtual 关键字 声明 函数 时 , C++ 编译器 会自动为该类生成 " 函数表 " ; 生成函数前提是 至少有...函数指针 : " 函数表 " 是 存储 " 类成员函数指针 " 数据结构 , 是一个 函数指针数组 , 数组中元素都是函数指针 , 具体存储都是 指向 类中函数 指针 ; 如果 子类...中 , 重写了 父类 virtual 函数 , 那么 C++ 编译器会在 子类 函数表 中放入该 子类函数 函数指针 ; 如果 C++ 类中存在 virtual 函数 , 在创建对象时 ,...会生成 函数表 Virtual Function Table , 简称 vtable ; C++ 编译器 编译 代码时 , 会自动为该类 添加 一个 vptr 指针 成员变量 , 该指针 会指向 函数

19740

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

C++三大特性之一多态是基于函数实现,而大部分编译器是采用函数表来实现函数函数表(VTAB)存在于可执行文件只读数据段中,指向VTAB指针(VPTR)是包含在类每一个实例当中。...当使用引用或指针调用函数时,首先通过VPTR找到VTAB,然后通过偏移量找到函数地址并调用。...vptr2[1](); 34 35 return 0; 36 } 运行结果: B1::bar D::foo D::bar \\\\\\ D::bar B2::foo 结论: 多重继承会有多个函数表...,几重继承,就会有几个函数表。...再简单总结一下 覆盖 隐藏 重载 区别: 覆盖 是C++函数实现原理,基类函数被子类重写,要求函数参数列表相同; 隐藏 是C++名字解析过程,分两种情况,基类函数有virtual,参数列表不同

2.7K10

深入解析C++函数继承:实现多态性与继承关系高级特性

这里写目录标题 函数 函数实现动态绑定 继承 抽象类 函数 函数是在C++中用于实现多态性一种特殊函数。它通过使用关键字"virtual"进行声明,在基类中定义,可在派生类中进行重写。...这使得在继承关系中,通过基类指针或引用调用函数时,可以根据实际对象类型来动态地确定要执行函数版本,实现多态性特性。...在C++中,当基类指针或引用指向派生类对象时,通过调用函数,可以实现对应于派生类特定实现。这种根据对象实际类型来确定调用哪个函数机制就是动态绑定。...test00(); system("pause"); return 0; } 继承 继承(Virtual Inheritance)是C++一种继承方式,用于解决多继承菱形继承问题。...在多重继承中,如果一个派生类从两个或更多基类继承,而这些基类又共同继承自同一个基类,就会出现菱形继承问题。这种情况下,派生类会包含同一个基类多份拷贝,导致二义性和内存浪费。

1.3K10

c++ 继承类强制转换时函数表工作原理

本文通过简单例子说明子类之间发生强制转换时函数如何调用,旨在对c++继承函数作用机制有更深入理解。...因为在类child2函数表中,共存在三个函数,分别为f() b() a(),其中函数b()是第二个,因此编译器就会把对象c1对应内存来当做类child2内存布局来解析(注意内存里内容不变,还是...c1,即为类child1内存布局,在这里只有函数表),此时在类child1函数表中也找第二个函数,找到了函数a(),因此输出“child1::a()”,运行正常。...但这种行为可能是危险,若使用内存布局并不适合真实内存,很可能造成访问越界等问题(如上例中“pc21->a();”,这次就在类B函数表中找第三个函数,结果没有找到(访问越界),函数运行时崩溃。)...2、通过上述例子可知,函数函数表中存储顺序是与声明顺序一致,而不是函数名字字符串排序,如本例中为f() b() a(),虽然编程时自动补全提示框中显示顺序是a() b() f(),但可能已经经过内部优化

1.1K30

从零开始学C++继承函数C++对象内存模型造成影响(类对象大小)

下面通过实例来展示继承函数对类大小造成影响。...: vtbl:函数表(存放函数函数指针) vptr:函数指针 ?...从成员输出地址和通过函数指针访问到函数可以画出模型: ? DD::vfdd 位置跟继承顺序有关,如果DD先继承是B2, 那么它将跟在B2::vfb2 下面。...注意:如果没有继承,则函数表会合并,一个类只会存在一个函数表和一个函数指针(同个类对象共享),当然也不会有基类表和基类表指针存在。...但如果是钻石继承,那么是会存在两份函数表和两份函数指针。 参考: 《深入探索C++对象模型》 C++ primer 第四版 Effective C++ 3rd C++编程规范

1K00

C++】多态 ⑩ ( 不建议将所有函数都声明为 virtual 函数 | 多态理解层次 | 父类指针和子类指针步长 )

对象可以直接获取到自身封装 普通函数 , 如果要访问函数 , 需要增加一次寻址操作 , 因此 这里建议不需要将有 多态 需求函数声明为 函数 ; C++ 中 指向某类型对象 指针 运算 ,...是 根据 指针类型 进行 , 指针 自增 ++ , 指针地址值 会增加 指针类型字节大小 ; 指针 步长 是 根据 指针 指向 内存空间 数据类型确定 ; 子类 继承 父类 , 如果 子类...没有添加任何 成员函数 与 成员方法 , 那么子类指针 与 父类指针 步长是相同 ; 一、不建议将所有函数都声明为 virtual 函数 C++ 类中 , 每个 成员函数 都可以声明为 virtual...调用 函数 可执行 子类对应函数 ; 多态实现条件 : ① 继承 , ② 函数重写 , ③ 父类指针/引用指向子类对象 ; 父类指针 可以 指向 父类对象 , 也可以指向 不同 子类对象 ;...是 根据 指针 指向 内存空间 数据类型确定 ; 子类 继承 父类 , 如果 子类 没有添加任何 成员函数 与 成员方法 , 那么子类指针 与 父类指针 步长是相同 ; 代码示例 : #include

24850

C++反汇编第三讲,反汇编中识别指针,以及指向函数地址

C++反汇编第三讲,反汇编中识别指针,以及指向函数地址 讲解之前,了解下什么是函数,什么是指针,了解下语法,(也算复习了) 开发知识为了不码字了,找了一篇介绍比较好,这里我扣过来了...定义纯函数是为了实现一个接口,起到一个规范作用,规范继承这个类程序员必须实现这个函数。...如果看明白上面的开发知识,则我们可以从内存角度看一下函数是怎么样存在. 2.从内存角度看函数 首先我们学习C++时候,自学或者老师教学时候,都有谈过一个指针概念....总结: 1.没有指针     1.1没有函数情况下没有指针   2.有指针     2.1指针产生是看你有没有 virtual这个关键字     2.2指针存储首地址...熟悉了指针, 通过指针找构造,析构,以及指针指向表找函数,那么我们看一下普通成员函数调用和函数调用有什么区别.

1.5K60

C++:29 --- C++继承关系下内存布局(下)

但是,C++为了我们方便,还提供了多重继承。 比如,我们有一个组织模型,其中有经理类(分任务),工人类(干活)。...当然,派生类数据本身也是按照声明顺序布局(本规则并非一成不变 ,我们会看到,当一些基类有函数而另一些基类没有时,内存布局并非如此)。 3. 继承 回到我们讨论一线经理类例子。...4 多重继承函数 如果从多个有函数基类继承,一个实例就有可能包含多个vfptr。考虑如下R和S类: ?...先根据P和R在S中偏移,调整this为P*,也就是S*,然后跳转到相应函数处执行。 在微软VC++实现中,对于有函数多重继承,只有当派生类函数覆盖了多个基类函数时,才使用调整块。...MSC++实现不是这样,MSC++有意将S::rvf编译为接受一个指向S中嵌套R实例,而非指向S实例指针(我们称这种行为是“给派生类指针类型与该函数第一次被引入时接受指针类型相同”)。

1.2K20

【笔记】《Effective C++》条款26-55

那么应该转用private继承防止误导用户 34 区分接口继承和实现继承 这部分是为了从语义上来理解C++继承设计 成员函数接口总是会被继承函数: 仅接口, 意味着希望派生类自己进行实现 非纯函数..., 令用户只修改核心部分, 但利用总接口来使用 NVI手法需要允许用户修改私有的函数, 这恰好是C++中"派生类可以重新定义继承私有函数, 因为继承而来函数与基类无关"这个特性应用 当派生类需要使用基类一些内容时函数也会被写为...protected NVI手法还可以进一步扩展为实现策略设计模式函数指针方法, 使用函数指针来替代函数, 这让我们可以动态改变每个对象某个行为 但是仅用函数指针还是太笨拙了, 使用标准库模板类std...这也是前面 条款7 和 条款34 一种解释 37 绝不重新定义继承而来缺省参数值 函数是动态绑定, 但是函数缺省参数值却是静态绑定, 只与你填写这个缺省参数值时类型有关, 与指针指向实际类型无关...这个规矩也就是Java等语言中对接口这种多重继承性质类有特殊设计原因 当用到这种基类作为接口时, 一般都采用公有继承, 因为其没有实际变量, 那么各种接口函数都应该是设计给用户使用 7 模板与泛型编程

90530

C++ 函数表解析

这里我们着重看一下这张函数表。C++编译器应该是保证函数指针存在于对象实例中最前面的位置(这是为了保证取到函数有最高性能——如果有多层继承或是多重继承情况下)。...多重继承(无函数覆盖) 下面,再让我们来看看多重继承情况,假设有下面这样一个类继承关系。注意:子类并没有覆盖父类函数。 ? 对于子类实例中函数表,是下面这个样子: ?...(所谓第一个父类是按照声明顺序来判断) 这样做就是为了解决不同父类类型指针指向同一个子类实例,而能够调用到实际函数多重继承(有函数覆盖) 下面我们再来看看,如果发生函数覆盖情况。...一、通过父类型指针访问子类自己函数 我们知道,子类没有重载父类函数是一件毫无意义事情。因为多态也是要基于函数重载。...但在运行时,我们可以通过指针方式访问函数表来达到违反C++语义行为

1K10

干货丨C++函数

C++函数作用主要是实现了多态机制。关于多态,简而言之就是用父类型别的指针指向其子类实例,然后通过父类指针调用实际子类成员函数。...多重继承(无函数覆盖) 下面,再让我们来看看多重继承情况,假设有下面这样一个类继承关系。注意:子类并没有覆盖父类函数。 ? 对于子类实例中函数表,是下面这个样子: ?...(所谓第一个父类是按照声明顺序来判断) 这样做就是为了解决不同父类类型指针指向同一个子类实例,而能够调用到实际函数多重继承(有函数覆盖) 下面我们再来看看,如果发生函数覆盖情况。...一、通过父类型指针访问子类自己函数 我们知道,子类没有重载父类函数是一件毫无意义事情。因为多态也是要基于函数重载。...但在运行时,我们可以通过指针方式访问函数表来达到违反C++语义行为

57741

函数实现原理

多重继承(无函数覆盖) 下面,再让我们来看看多重继承情况,假设有下面这样一个类继承关系。注意:子类并没有覆盖父类函数。...(所谓第一个父类是按照声明顺序来判断) 这样做就是为了解决不同父类类型指针指向同一个子类实例,而能够调用到实际函数多重继承(有函数覆盖) 下面我们再来看看,如果发生函数覆盖情况。...一、通过父类型指针访问子类自己函数 我们知道,子类没有重载父类函数是一件毫无意义事情。因为多态也是要基于函数重载。...编译出错 任何妄图使用父类指针想调用子类中未覆盖父类成员函数行为都会被编译器视为非法,所以,这样程序根本无法编译通过。...但在运行时,我们可以通过指针方式访问函数表来达到违反C++语义行为

36820

C++ 虚拟继承

1.为什么要引入虚拟继承 虚拟继承多重继承中特有的概念。虚拟基类是为解决多重继承而出现。如:类D继承自类B1、B2,而类B1、B2都继 承自类A,因此在类D中两次出现类A中变量和函数。...虚拟继承在一般应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在必要因为这样只会降低效率和占用更多空间。...为什么需要继承? 由于C++支持多重继承,那么在这种情况下会出现重复基类这种情况,也就是说可能出现将一个类两次作为基类可能性。比如像下面的情况 ?...2.1时间:在通过继承类对象访问基类对象中成员(包括数据成员和函数成员)时,都必须通过某种间接引用来完成,这样会增加引用寻址时间(就和函数一样),其实就是调整this指针以指向基类对象,只不过这个调整是运行时间接完成...这说明:空类所占空间为1,单一继承空类空间也为1,多重继承空类空间还是1.但是继承涉及到表(指针),所以sizeof(C)大小为4 我相信经过上面的分析和对比,以后看到这类问题不会再疑惑,会有一种

2.3K80

c++类和继承面试点25连问

2. c++继承优点和缺点 优点:根据第1点中讲,其实继承优点就是实现了代码重用和接口重用; 缺点:子类会继承父类部分行为,父类任何改变都可能影响子类行为,也就是说,如果继承下来实现不适合子类问题...运行时多态简单来讲就是:使用基类指针或者引用指向一个派生类对象,在非虚继承情况下,派生类直接继承基类指针,然后使用派生类函数去覆盖基类函数,这样派生类对象通过指针访问到函数就是派生类函数了...更详细说明请看之前写这篇文章:c++头脑风暴-多态、继承多重继承内存布局 6....以上三种情况都必须使用初始化列表而不能在构造函数中进行赋值。 10. 什么情况下要使用继承多重继承时需要使用继承,一般我们在多重继承时使用继承来防止二义性问题。...多重继承时类对象内存布局 非虚继承时,按照继承顺序存储,继承时,基类内容放在一块内存最后面存储。 详细看之前这篇文章:c++头脑风暴-多态、继承多重继承内存布局 21.

93910

C++多态

本章内容旨在解决以下几个问题: 什么是 C++ 多态, C++ 多态实现原理是什么 什么是函数函数实现原理是什么 什么是表,内存结构布局如何,第一项(或第二项)是什么 菱形继承(...多重继承(无函数覆盖)时,每个父类都有自己表,且子类成员函数被放到了第一个父类表中。...多重继承(有函数覆盖)时,父类表中对应函数地址将被子类函数地址覆盖,子类新加函数地址将被添加到第一个父类函数表之后。...不同数据类型会进行对齐 2.对于多重继承多重继承几个基类就有几个指针。...当存在多重继承时,多重继承了几个基类,子类将含有几个指针,并且此指针具有传递性。

1.8K10

函数

因此,在析构函数中,函数机制也是不起作用。   C++函数作用主要是实现了多态机制。关于多态,简而言之就是用父类型别的指针指向其子类实例,然后通过父类指针调用实际子类成员函数。...多重继承(无函数覆盖)   下面,再让我们来看看多重继承情况,假设有下面这样一个类继承关系。注意:子类并没有覆盖父类函数。   ...多重继承(有函数覆盖)   下面我们再来看看,如果发生函数覆盖情况。   下图中,我们在子类中覆盖了父类f()函数。   ...一、尝试:通过父类型指针(指向子类对象)访问子类自己函数   我们知道,子类没有重载父类函数是一件毫无意义事情。因为多态也是要基于函数重载。...但在运行时,我们可以通过指针方式访问函数表来达到违反C++语义行为

81431
领券