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

在具有虚函数的多继承类的两个父类之间进行强制转换会导致奇怪的行为

在具有虚函数的多继承类的两个父类之间进行强制转换可能会导致奇怪的行为。这是因为多继承中存在着不同父类的指针或引用指向同一个对象的情况,而强制转换可能会破坏对象的内存布局,导致未定义的行为发生。

在C++中,多继承是一种同时从多个父类继承属性和行为的机制。当一个类继承自多个父类时,它会继承每个父类的成员变量和成员函数。如果这些父类中有虚函数,那么派生类也会继承这些虚函数。

在进行强制转换时,如果将一个指向派生类对象的指针或引用转换为其中一个父类的指针或引用,通常是安全的,因为派生类对象中包含了父类的成员。但是,如果将一个指向派生类对象的指针或引用转换为另一个父类的指针或引用,就可能会导致问题。

这是因为在多继承中,不同的父类可能具有相同的函数名,但其实现可能不同。当进行强制转换时,编译器可能会将指针或引用的类型视为目标父类类型,导致调用错误的函数实现。这可能会导致程序运行时出现奇怪的行为,例如调用错误的函数或访问错误的成员变量。

为了避免这种奇怪的行为,应该尽量避免在具有虚函数的多继承类中进行父类之间的强制转换。如果确实需要进行转换,可以考虑使用dynamic_cast运算符进行安全的类型转换。dynamic_cast会在运行时检查转换的有效性,并在转换失败时返回nullptr或抛出异常,以避免出现未定义的行为。

总结起来,强制转换具有虚函数的多继承类的两个父类之间可能会导致奇怪的行为。为了避免这种情况,应尽量避免进行这种转换,或者使用dynamic_cast进行安全的类型转换。

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

相关·内容

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

本文通过简单例子说明子类之间发生强制转换时虚函数如何调用,旨在对c++继承中的虚函数表的作用机制有更深入的理解。...因为在类child2的虚函数表中,共存在三个函数,分别为f() b() a(),其中函数b()是第二个,因此编译器就会把对象c1对应的内存来当做类child2的内存布局来解析(注意内存里的内容不变,还是...c1的,即为类child1的内存布局,在这里只有虚函数表),此时在类child1的虚函数表中也找第二个函数,找到了函数a(),因此输出“child1::a()”,运行正常。...但这种行为可能是危险的,若使用的内存布局并不适合真实内存,很可能造成访问越界等问题(如上例中的“pc21->a();”,这次就在类B的虚函数表中找第三个函数,结果没有找到(访问越界),函数运行时崩溃。)...,因此使用强制转换操作时应特别注意。

1.2K30

23.C++- 继承的多种方式、显示调用父类构造函数、父子之间的同名函数、virtual虚函数  上章链接: 22.C++- 继承与组合,protected访问级别

C++中,继承方式共有3种: public继承 -指父类的成员(变量和函数)访问级别,在子类中保持不变 private继承 -指父类的成员,在子类中变为private私有成员....-也就是说子类无法访问父类的所有成员 protected继承 -指父类的public成员 ,在子类中变为protected保护成员,其它成员级别保持不变 如下图所示: ?...,编译器会默认调用父类无参构造函数 若有子类对象,也会默认调用子类对象的无参构造函数。...如果父类对象想访问子类的成员,只能通过强制转换,将父类对象转为子类类型 示例1,通过C方式转换: Child c; Parent* p3=&c; Child *c2 = (Child*)p3;...所以C++引入了虚函数概念,根据指针指向的对象类型,来执行不同类的同名覆盖成员函数,实现不同的形态 定义: 在父类成员函数的返回值前面,通过virtual关键字声明,这样便能访问子类中的同名成员函数了

3.2K90
  • 【C++进阶篇】像传承家族宝藏一样理解C++继承

    C++的继承机制正是通过类与类之间的继承关系来模拟这些现实中的关系。继承使得开发者能够从一个基类派生出多个派生类,从而共享基类的行为,并在需要时对其进行扩展或修改。...C++继承的关键要点: 代码重用:继承使得子类能够复用父类的属性和方法,减少重复代码。 扩展性:通过继承,子类可以扩展或修改父类的行为,从而实现系统的扩展。...多态性:继承和虚函数的结合使得C++能够实现运行时多态,从而使代码更加灵活和动态。 多继承与虚继承:C++支持多继承和虚继承,这为开发者提供了强大的功能,但也增加了代码设计的复杂度。...5.1.1 函数的隐藏 在C++中,函数隐藏指的是子类中定义的一个与父类中已有的成员函数具有相同名称和参数列表的函数,导致父类的函数在子类中被“隐藏”或“遮蔽”的现象。...内存泄漏:如果基类的析构函数不是虚函数,那么派生类的析构函数不会被调用,可能会导致资源没有得到正确释放,从而引发内存泄漏。

    10810

    C#中的override和new关键字

    如果对Java熟悉的朋友,可能会认为是结果: 这是父类方法 这是子类方法 但是其实运行结果是: 这是父类方法 这是父类方法 这是因为Java中的类方法默认是虚函数(虽然Java中没有这个叫法),子类函数会默认覆盖父类的同名函数...然而C#中必须使用virtual关键字显示声明该函数是虚函数,然后在子类中使用override关键字重写父类方法,这才真正实现了对父类方法的重写,才能实现多态(C++中的多态就是使用虚函数实现的,而且和...正确的结果是: 使用override关键字修饰的方法 这是一个虚方法 为什么使用关键字new修饰的方法,调用的是父类的方法呢? 是不是很奇怪?...所以 c2.fun()会调用父类的fun()方法,要想调用C2的fun()方法必须吧c2强制转换为C2. ---- 下面看看微软官方的文档解释: C# 语言经过专门设计,以便不同库中的基类与派生类之间的版本控制可以不断向前发展...这具有多方面的意义。例如,这意味着在基类中引入与派生类中的某个成员具有相同名称的新成员在 C# 中是完全支持的,不会导致意外行为。

    1.3K20

    【C++】从零开始认识多态

    继承就是可以将类对象进行继承,派生类会继承基类的功能与属性,类似父与子的关系。比如水果和苹果,苹果就有水果的特性。 接下来我们就来了解学习多态!...多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。...override关键字的区别: 抽象类间接强制了派生类必须进行虚函数重写 override是在已经重写的情况下,帮助进行重写的语法检查 6 多继承中的多态 多继承我们讲过,是一种很危险的继承,很容易导致菱形继承...那么Derive由于多继承的缘故会包含两个基类,所以应该为16 + 4 = 20字节: 运行一下,看来我们的分析没有问题!...所以BC会独立创建一个虚表指针。 总结: 子类有虚函数,继承的父类有虚函数就有虚表,子类不需要单独建立虚表!!!如果父类是共享的,无论如何都有创建独立的虚表!!!

    9110

    【C++】三大特性之多态

    ---- 二、多态的定义及实现 1.多态的构成条件 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如 Student 继承了 Person 。...那么在继承中要 构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 2.虚函数 我们在讲继承的菱形继承的时候曾经说到过虚拟继承...,派生类的虚函数在不加  virtual 关键字时,虽然也可以构成重写 ( 因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性), 但是该种写法不是很规范,不建议这样使用 虚函数重写的两个例外...我们强制类型转换成 int* 就是为了取到四个字节,但是在32位下是4字节,在64位下是8字节的只有指针了,所以我们强制类型转换为二级指针就行了。这样解引用的时候,得到的一级指针就是占用8字节的了。...补充: 为什么构成多态有两个条件:一个是虚函数覆盖,一个是父类对象的指针或引用调 用虚函数。直接是父类对象不行吗? 答案:不行。

    78250

    深入理解面向对象编程特性 : 继承

    Base baseObj; Derived derivedObj; // 以下赋值会导致编译错误 // derivedObj = baseObj; 父类的指针或引用可以通过强制类型转换赋值给子类的指针或引用...} else { // 转换失败,basePtr并不指向Derived对象 } 强制类型转换 虽然可以使用static_cast进行强制转换,但这种转换在父类指针不指向子类对象时是危险的。...= p2 菱形继承 菱形继承是多继承中的一种特殊情况,发生在一个子类通过两个不同的路径继承自同一个基类时,形成菱形结构。 这种继承方式会带来数据冗余和访问二义性的问题。...在多继承中,如果一个子类通过不同的路径从同一个基类继承,那么就会形成菱形继承。菱形继承会导致子类中存在多个基类实例,从而产生数据冗余和访问二义性的问题。...继承与组合的比较 复用性:继承可以直接复用父类的实现,组合则通过使用已有类的实例来复用功能。 耦合度:继承会导致子类与父类的紧密耦合,组合则保持类之间的独立性。

    15810

    【C++高阶】多态(概念&&虚函数&&抽象类)

    比如:如果是x64程序,则需要考虑指针是8bytes问题 一、多态的定义及实现 1.1 多态的定义 多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。...{ public: virtual void BuyTicket() { cout << "买票-全价" << endl;} }; 1.2.2 虚函数的重写 虚函数想要构成重写需要以下条件:这两个函数一个在子类一个在父类...; } }; 5.virtual的两个关键字(override和final) C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的...四、单继承和多继承关系的虚函数表 需要注意的是在单继承和多继承关系中,下面我们去关注的是派生类对象的虚表模型,因为基类的虚表模型前面我们已经看过了,没什么需要特别研究的 4.1 单继承中的虚函数表...return 0; } 4.2 多继承中的虚函数表 我们要想打印第二张虚表就必须跳过第一张,我们来分析一下 ((char*)&d+sizeof(Base1)) 观察下图可以看出:多继承派生类的未重写的虚函数放在第一个继承基类部分的虚函数表中

    17010

    【C++】多态

    ,类对象的存储模型和以前不一样了,类对象会多一个虚表指针。...我们也有两种解决办法,一种就是在类型转换时将对象地址强制类型转换为二级指针,这样在解引用的时候,拿到的就是一级指针,一级指针的大小在32位和64位平台是不同的值,那么我再将指针转换为虚函数地址类型就可以了...多继承之后的派生类有两张虚表,那派生类自己的虚函数会放在哪里呢?...Drive的大小,这里会崩,需要改成char*,指针+-整数,跳过指针类型字节的大小 //如果多继承的类有虚函数,他的虚函数会放到第一个类的虚表里面。...纯虚函数所在的类称之为抽象类,抽象类会强制其派生类重写纯虚函数,因为如果不重写纯虚函数,派生类也无法实例化出对象,那就失去了其存在的意义。

    55220

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

    error报错, 编译期的方法是额外分出细化的基类, 然后让特定的方法只在特定的基类中有对应的虚函数可重写(覆盖) 33 避免遮掩继承而来的名称 当一个名称同时在小作用域和大作用域中存在时, C++会进行遮掩...(name-hiding), 至于这两个名称类型是否相同并不被考虑 这是非常危险的特性, 如下图派生类中的mf3函数会将基类的两个mf3一起进行遮掩, 无论基类那两个函数类型和形式是什么样的 因此对于公有继承来说...(empty base optimization)的原因不会占用额外的字节 40 明智而审慎地使用多重继承 多重继承可能会导致很多歧义, 例如要调用两个基类都有的同名函数时, 需要进行匹配性计算, 这个匹配计算与函数的访问性无关..., 只和重载一样和名称与参数有关, 所以很容易二义 更复杂的情况是下图的"菱形继承": 菱形继承中, 对于不同基类都拥有的同名成员, C++默认会复制多份以供使用, 如果不希望复制就应该使用虚继承,...45 运用成员函数模板接受所有兼容类型 模板之间并没有什么类似继承关系的固有关系, 无法自动在继承类之间进行隐式转换, 智能指针类通过底层的转型来模拟这种关系 方法是编写用于指针间类型转换的构造模板,

    93330

    EasyC++87,多继承(二)

    这是EasyC++系列的第87篇,我们继续来聊聊多继承 多继承(二) 在上一篇文章当中我们聊了多继承菱形的问题,在多继承菱形出现的时候,会导致派生类当中包含两个同样的父类实例。...上一篇结尾处我们介绍了使用强制类型转换来避免歧义的办法,强制类型转换只是无奈之举,并且还有一个问题解决不了。...所以强制类型转换虽然能解决歧义,但不能根本上解决问题。 想要从根源上解决问题,需要使用C++官方提供的一个新的功能——虚基类。...虽然这里使用的也是virtual关键字,但虚函数和虚基类之间并没有任何关联,只不过是C++官方不愿意引入更多关键字以免造成使用者的负担而已。...使用了虚基类之后,一些语法会和之前有所不同,接下来我们来详细介绍。 构造函数 对于非虚基类的继承关系来说,我们可以在构造函数当中将数据传递给基类。

    39810

    【C++】继承和多态

    复杂的菱形继承及菱形虚拟继承 (1)继承类型 1. 单继承:一个子类只有一个直接父类时称这个继承关系为单继承。 2. 多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承。 3....(1)多态的构成条件 那么在继承中要构成多态还有两个条件: 必须通过父类的指针或者引用调用虚函数; 被调用的函数必须是虚函数,且子类必须对父类的虚函数进行重写; 我们先简单看一下多态的使用,如以下代码:...单继承中的虚函数表 需要注意的是在单继承和多继承关系中,下面我们去关注的是子类对象的虚表模型,因为父类的虚表模型前面我们已经看过了,没什么需要特别研究的。我们这里就只看单继承的中的虚函数表。...多继承中的虚函数表 假设一个类是多继承下来的,这个类有几个父类,如果父类都有虚函数,则就会有几张虚表,这个类自身不会产生多余的虚表;如果这个类自身也有虚函数呢?...例如我们有以下三个类,A,B,C,其中 C 继承 A 和 B,属于多继承,A 和 B 中都有虚函数,C 中也对 A 、B 中的虚函数进行重写,C 中再增加自己的虚函数;如下三个类: class A

    17110

    【C++】看不懂多态?这篇文章带你吃透它!

    假设这里没有用 virtual 修饰基类的 BuyTicket() 函数,那么这两个派生类的同名函数与基类之间就构成了隐藏,而不是重写!...,后两个析构是 p2 所指对象的析构,分别调了派生类和父类的析构函数完成析构,符合继承原理!...,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来 debug 会得不偿失,因此 C++11 提供了 override...在多继承中,派生类对象自己的成员函数是存在第一个继承基类部分的虚函数表的。 在内存布局中,父类的布局是依次 按声明顺序排列 的。 设计对象模型时候 避免出现菱形继承,因为比较复杂,容易搞错!...注意这里不要把虚函数表和虚基表搞混了。 什么是抽象类?抽象类的作用?答:参考(3.抽象类)。抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。

    7010

    【多态】【虚表指针与虚表】【多继承中的多态】

    假设这里没有用 virtual 修饰基类的函数,那么这两个派生类的同名函数与基类之间就构成了隐藏(继承里的知识),那么通过 Fun 函数,我们只能调用到 Person 类的同名函数,因为形参里面的对象类型就是...,后两个析构是 p2 所指对象的析构,分别调了派生类和父类的析构函数完成析构,符合继承原理!...final 和 override 从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来...多继承中的虚函数表 多继承中的虚表那就更复杂啦!...,多继承的派生类会生成多份虚表,也就印证了一个道理:一个对象的虚表不只有一张!

    1.2K30

    【旧文重发 | 06】IC基础知识

    这可以通过SystemVerilog中的继承和虚函数的概念(以及C++中存在的函数和运算符重载的概念)来实现。根据对象的类型,将从相应的类中调用适当的方法。...[110] OOP中的组合(composition)和继承(inheritance)之间有什么区别? 组合使两个类之间具有“has - a”关系。...当一个类实例化另一个类的对象时,该关系为“ has-a”,并且此属性称为composition。 继承使两个类之间具有“is - a”关系。...[113] 什么是多重继承? 多重继承是某些面向对象的计算机编程语言的功能,其中对象或类可以从多个父对象或父类继承特征和功能。它不同于单一继承,在单一继承中,一个对象或类只能从一个特定的对象或类继承。...编译器自动将一种数据类型转换为另一种数据类型称为"type conversion"。 应用 类型强制转换也可以应用于两个"不兼容"的数据类型。 仅当两个数据类型"兼容"时,才能实现类型转换。

    1.1K20

    【C++】继承

    ,因为中间产生的临时变量具有常性,需要用const引用 //基类与派生类对象的赋值转换也叫做向上转换,但是不能向下转换,因为父类缺少子类中特殊的那一部分,无法进行赋值转换。...复制重载和拷贝构造有一点不一样,由于复制重载函数名在基类和子类中函数名相同,所以在调用基类的复制重载时必须指定基类域,否则会导致死循环调用子类复制重载,最终导致堆栈溢出。...某些较小版本的编译器会对内置类型进行处理,但我们不可以依赖编译器的这种行为,因为将来我们的程序必须具有良好的移植性,如果你的代码换平台之后出现了问题,那么请记住,一定是你的代码出现了问题,和平台是没什么关系的...cout << "~Student()" << endl; //在子类对象析构函数调用之后,编译器又会自动调用父类析构,这是编译器的默认行为。...菱形继承就是在多继承的基础上,多继承的父类还有一个共同的父类,这就会导致菱形继承的出现,基类中的成员在多继承的子类中会出现多份数据占用内存的情况,即数据冗余问题的出现,并且在访问多继承子类的基类成员时,

    71010

    【c++】全面理解C++多态:虚函数表深度剖析与实践应用

    多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。...Person对象买票全价,Student对象买票半价 那么在继承中要构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 指向谁调用谁...我们进行调试 Johnson首先继承了父类的部分,有虚表和虚表指针,这两个虚表指针不一样,他们指向内容不一样,一个指向父类的Buyticket,另一个指向子类的 p是指向mike对象时,p->BuyTicket...,继承了两个父类,两个父类的虚表不能合在一起,这里对两张虚表都进行了重写,那么这里func3放在哪个虚表中了呢,是都放呢还是只放一个呢?...在多继承和虚继承的情况下,这个顺序变得更加复杂。

    33800

    【C++】C++中的继承,看这一篇就够了

    基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的 三. 继承中的作用域 在继承体系中基类和派生类都有独立的作用域。...派生类的默认成员函数 6个默认成员函数,“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?...那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系 五....复杂的菱形继承及菱形虚拟继承 单继承:一个子类只有一个直接父类时称这个继承关系为单继承 多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承 菱形继承:菱形继承是多继承的一种特殊情况...(2)菱形继承是指一个类同时从两个直接或间接的基类继承,而这些基类又共同继承自同一个基类,形成了一个菱形结构。这种情况下,可能会导致数据冗余和访问不明确(二义性)的问题。

    11710

    C++ 继承

    这里要实例化不然找不到pushback vector::push_back(x); } }; 基类于派生类之间的转换 public继承的派生类 可以 被 基类的指针 或 引用 派生类的指针或引用不可以指向基类...基类的指针或者引⽤可以通过强制类型转换赋值给派⽣类的指针或者引⽤。...,会导致数据很多,而且对某些数据还有歧义,因为“隐藏”的原因,这个源于“原始基类”的数据被多次继承,每一个继承都有一个‘隐藏’,数据多而且乱七八糟,并不建议菱形继承,有些语言甚至没有多继承 class...public A{}; class D:public A,public B{}; 一、节省内存空间 在多重继承中,如果不使用虚继承,一个基类可能会因为被不同的派生类从不同路径继承而导致其数据成员在派生类中存在多份拷贝...编译器在面对这种情况时,无法确定应该访问哪一份基类的拷贝,从而导致编译错误或不确定的行为。虚继承通过共享基类数据成员的方式消除了这种二义性,使得在派生类中访问基类成员变得明确且唯一。

    4610

    Google C++ 编程风格指南(三):类

    构造函数的职责 不要在构造函数中进行复杂的初始化 (尤其是那些有可能失败或者需要调用虚函数的初始化). 定义: 在构造函数体中进行初始化操作. 优点: 排版方便, 无需担心类是否已经初始化....这会让人迷惑, 尤其是对那些所用的语言约定或强制要求传引用的程序员来说更是如此. 同时, 这从一定程度上说会鼓励过度拷贝, 从而导致性能上的问题. 结论: 如果需要就让你的类型可拷贝 / 可移动....在类没有实现 API 中某个必须的方法时, 编译器同样会发现并报告错误. 缺点: 对于实现继承, 由于子类的实现代码散布在父类和子类间之间, 要理解其实现变得更加困难....当重载一个虚函数, 在衍生类中把它明确的声明为 virtual. 理论依据: 如果省略 virtual 关键字, 代码阅读者不得不检查所有父类, 以判断该函数是否是虚函数. 3.8....更难定位重载运算符的调用点, 查找 Equals() 显然比对应的 == 调用点要容易的多. 有的运算符可以对指针进行操作, 容易导致 bug.

    83040
    领券