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

虚函数在继承中表现得很奇怪?

虚函数在继承中的表现确实可能会有些奇怪,这是因为虚函数的多态特性可能会导致一些意想不到的结果。虚函数是一种特殊的成员函数,它允许在派生类中重写基类中的同名函数,从而实现多态性。

在继承中,虚函数的表现可能会受到以下因素的影响:

  1. 动态绑定:虚函数的调用是在运行时动态绑定的,这意味着在运行时才确定调用哪个函数。这可能会导致在派生类中重写的函数没有被正确调用。
  2. 构造函数和析构函数:在构造函数或析构函数中调用虚函数可能会导致意想不到的结果,因为虚函数的多态特性在对象的构造和析构过程中可能会出现问题。
  3. 静态绑定:在基类的构造函数或析构函数中调用虚函数时,由于对象尚未完全构造或已经开始析构,虚函数的调用可能会被静态绑定到基类的函数,而不是派生类中的函数。
  4. 纯虚函数:如果基类中的虚函数被声明为纯虚函数,那么在派生类中必须重写该函数,否则派生类也将变为抽象类。

为了避免虚函数在继承中的奇怪表现,可以采取以下措施:

  1. 避免在构造函数和析构函数中调用虚函数。
  2. 使用动态类型转换来确保正确调用虚函数。
  3. 在派生类中重写基类中的虚函数,并确保正确调用基类中的虚函数。
  4. 使用纯虚函数来强制派生类重写该函数。

推荐的腾讯云相关产品:

  1. 腾讯云云服务器:提供高性能、高可用、可扩展的云服务器,支持一键部署和自定义配置。
  2. 腾讯云对象存储:提供可扩展、安全、低成本的云存储服务,支持 RESTful API 和 SDK。
  3. 腾讯云数据库:提供 MySQL、PostgreSQL、MongoDB 等多种数据库服务,支持自动备份和故障切换。
  4. 腾讯云容器服务:提供弹性、可扩展的容器解决方案,支持 Kubernetes 和 Docker 容器。

产品介绍链接地址:

  1. 腾讯云云服务器:https://cloud.tencent.com/product/cvm
  2. 腾讯云对象存储:https://cloud.tencent.com/product/cos
  3. 腾讯云数据库:https://cloud.tencent.com/product/cdb
  4. 腾讯云容器服务:https://cloud.tencent.com/product/tke
页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别

如下就是一个父类中的虚函数: class A { public: virtual void out2(string s) { cout<<"A(out2):"<<s<<endl...; } }; 2.纯虚函数(pure virtual)        C++中包含纯虚函数的类,被称为是“抽象类”。...抽象类不能使用new出对象,只有实现了这个纯虚函数的子类才能new出对象。   C++中的纯虚函数更像是“只提供申明,没有实现”,是对子类的约束,是“接口继承”。   ...C++中的纯虚函数也是一种“运行时多态”。   ...普通函数是父类为子类提供的“强制实现”。   因此,在继承关系中,子类不应该重写父类的普通函数,因为函数的调用至于类对象的字面值有关。

2K30

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

那么在继承中要构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 2.2 虚函数 虚函数:即被virtual修饰的类成员函数称为虚函数...,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因 为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议 这样使用*/ /*void BuyTicket...nullptr 总结一下派生类的虚表生成:a.先将基类中的虚表内容拷贝一份到派生类虚表中 b.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后...的虚表中找到虚函数是Person::BuyTicket 观察下图的蓝色箭头我们看到,p是指向johnson对象时,p->BuyTicket在johson的虚表中 找到虚函数是Student::BuyTicket...单继承和多继承关系中的虚函数表 5.1 单继承中的虚函数表 class Base { public: virtual void func1() { cout << "Base::func1" <<

38510
  • 深入解析C++中的虚函数和虚继承:实现多态性与继承关系的高级特性

    这里写目录标题 虚函数 虚函数实现动态绑定 虚继承 抽象类 虚函数 虚函数是在C++中用于实现多态性的一种特殊函数。它通过使用关键字"virtual"进行声明,在基类中定义,可在派生类中进行重写。...这使得在继承关系中,通过基类指针或引用调用虚函数时,可以根据实际对象的类型来动态地确定要执行的函数版本,实现多态性的特性。...虚函数定义 在 C++ 中,可以通过在函数声明前面加上关键字 virtual 来定义虚函数。...纯虚函数(Pure Virtual Function)是在基类中声明的没有实际实现的虚函数。它通过在函数声明后面加上= 0来表示。 纯虚函数在基类中起到了接口的定义作用,要求派生类必须提供对应的实现。...Derived类继承自Base类,并提供了对纯虚函数的具体实现。通过Derived类的对象或基类指针可以调用纯虚函数的具体实现。 纯虚函数允许在基类中定义一组接口,并强制要求派生类提供相应的实现。

    2.1K10

    派生类对基类中虚函数和非虚函数的继承效果

    而虚函数的作用,主要是为了让父类指针可以调用子类的函数,这种是在运行时才决定调用哪个函数 1、虚函数:   C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现。...子类可以重写父类的虚函数实现子类的特殊化。 2、纯虚函数:   C++中包含纯虚函数的类,被称为是“抽象类”。抽象类不能使用new出对象,只有实现了这个纯虚函数的子类才能new出对象。   ...C++中的纯虚函数更像是“只提供申明,没有实现”,是对子类的约束,是“接口继承”。   C++中的纯虚函数也是一种“运行时多态”。...3、普通函数:   普通函数是静态编译的,没有运行时多态,只会根据指针或引用的“字面值”类对象,调用自己的普通函数。   普通函数是父类为子类提供的“强制实现”。   ...因此,在继承关系中,子类不应该重写父类的普通函数,因为函数的调用至于类对象的字面值有关。 参考链接

    9210

    C++ 虚函数详解:多态性实现原理及其在面向对象编程中的应用

    C++是一种面向对象的编程语言,在C++中,虚函数是实现多态性的关键 什么是虚函数 虚函数是一个在基类中声明的函数,它可以被子类重写并提供不同的实现。...在C++中,使用关键字virtual来声明一个虚函数。虚函数的原理是将函数调用的控制权交给运行时环境,而不是编译时环境。因此,虚函数的实现需要在运行时才能确定。...注意,在Circle类中的重写函数中使用了override关键字,这是C++11中引入的新特性,表示该函数是对基类中同名函数的重写。...这种行为称为运行时多态性,因为实际调用的函数是在运行时确定的。 多态的底层原理 在C++中,多态是通过虚函数表和虚指针来实现的。虚函数表是一个特殊的表格,其中包含了虚函数的地址。...总结 虚函数是实现多态性的关键,它允许不同的对象表现出不同的行为。当使用基类指针或引用来访问派生类对象时,虚函数将调用派生类中的实现,实现了运行时多态性。

    1.1K10

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

    由于会改变函数表的指向且需要进行大量继承分析, 因此这个转型很危险且很多时候执行得很慢....考虑virtual函数的其他选择 非虚拟接口(non-virtual interface; NVI)手法: 令用户通过非虚公有函数来间接调用私有虚函数, 是模板方法设计模式的一种表现 NVI手法的目的是在核心虚函数外面完成一些特定的外带行为..., 令用户只修改核心部分, 但利用总的接口来使用 NVI手法需要允许用户修改私有的虚函数, 这恰好是C++中"派生类可以重新定义继承来的私有虚函数, 因为继承而来的虚函数与基类无关"这个特性的应用 当派生类需要使用基类的一些内容时虚函数也会被写为...这种特性会在你试图使用多态的缺省参数值时产生非常奇怪的效果, 因此千万不要重新定义 这种需求可以用NVI手法进行一定程度的解决, 因为协议中我们永远不应该重写非虚函数, 所以在非虚函数中设置缺省参数是安全的...令我们想要承载数据的那个基类成为虚基类 虚基类让编译器动态计算成员所需的位置从而匹配, 但是使用了虚继承的类产生的对象会比非虚继承的对象又大又慢 所以非必要不要使用虚继承, 如果一定要用, 那么别在虚基类中防止成员数据

    93330

    探索C++对象模型

    ,这也符合我们的常识.所以这个简单的对象在内存中主要表现为存储非静态数据成员和虚函数.更具体而言一个对象会保存非静态数据成员和一个指向虚函数表的指针(vfptr,如果有虚函数的话),我们常说C++的编译器会偷偷做很多事情这里便是一个例子...),不过这个不再讨论范围内); 下面是详细的验证, int main() { base b; //在vs的编译器实现中虚函数表指针放在对象抵首位,所以&b也就相当于取vfptr地址;...单继承对象模型 只要明白了简单对象模型接来的单/多继承也就变得很简单了....基类数据成员会放置在指向该基类的虚函数表的指针下面,如果有必要之类还会进行内存alignment....,在单继承下派生类内存模型会储存基类的数据成员和虚函数,所以这里base1和base2分别储存了rootData和print(),最后derived的多重继承把每个相对于它而言的基类一块一块的放入内存,

    53430

    C++ 虚拟继承

    1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继 承自类A,因此在类D中两次出现类A中的变量和函数。...,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要因为这样只会降低效率和占用更多的空间。...2.引入虚继承和直接继承会有什么区别呢 由于有了间接性和共享性两个特征,所以决定了虚继承体系下的对象在访问时必然会在时间和空间上与一般情况有较大不同。...2.1时间:在通过继承类对象访问虚基类对象中的成员(包括数据成员和函数成员)时,都必须通过某种间接引用来完成,这样会增加引用寻址时间(就和虚函数一样),其实就是调整this指针以指向虚基类对象,只不过这个调整是运行时间接完成的...一个虚基类子对象只会在派生类中存在一份实体,不管他在继承体系中出现多少次,所以公用一个1byte的classX实体,再加上 class Y和class Z这样就有9bytes,如果有对齐的话就是12bytes

    2.4K80

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

    Animal 类中声明了一个虚函数 speak(),该函数在声明时使用了 virtual 关键字。Cat 类继承了 Animal 类,并覆盖了 speak() 函数。 ​...如果派生类重写了基类中某个虚函数,用派生类自己的虚函数指针覆盖虚表中基类的虚函数指针。 派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。...在多继承中,派生类对象自己的成员函数是存在第一个继承基类部分的虚函数表的。 在内存布局中,父类的布局是依次 按声明顺序排列 的。 设计对象模型时候 避免出现菱形继承,因为比较复杂,容易搞错!...如果派生类有自己的虚函数,由于 vs 编译器的原因无法在监视窗口的派生类对象中的虚表观察到,所以我们可以自己写个程序确认一下是否存在虚表中,结果也证实了 派生类自己的虚函数在虚表中是存在的,只不过没有在监视窗口展现出来...也称为黑盒复用 ​ C:优先使用继承,而不是组合,是面向对象设计的第二原则 ​ D:继承可以使子类能自动继承父类的接口,但在设计模式中认为这是一种破坏了父类的封装性的表现 以下关于纯虚函数的说法,正确的是

    7010

    C++反汇编第五讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式.

    C++反汇编第五讲,认识多重继承,菱形继承的内存结构,以及反汇编中的表现形式....目录:   1.多重继承在内存中的表现形式     多重继承在汇编中的表现形式   2.菱形继承     普通的菱形继承     虚继承     汇编中的表现形式 一丶多重继承在内存中的表现形式 高级代码.... 2.在父类2指向子类的时候,会产生三木目运算的表达式. 2.观看反汇编中的表现形式. 1.main函数下,构造位置处 ?...构造父类1,构造父类2之后的内存结构图,最后子类自己的构造中需要复写两个父类自己的虚表.而且自己扩展的虚函数会放在父类1的虚表中....从反汇编和内存中可以看出,每一个父类都有一个自己的爷爷类.而且每个父类构造爷爷类的时候,都会填写爷爷类的虚表,并且在自己的构造中对其复写(重写) 所以形成了下面这样的图 ?

    83070

    C++面向对象程序设计_Part2

    另外,Component类中还有一个虚函数add,这是给目录进行继承的,因为目录可以新建目录和文件,这里不能设置为纯虚函数,因为文件不能继承这个函数,文件是不能在进行添加的。 Prototype ?...A类内存中第一个就是虚指针,指向虚表,虚标里面有两个指针指向A的两个虚函数,下面两个是A类的数据,B类的前三个是继承了A类的数据以及虚指针,不同的是B类重新定义了vfunc1函数,这将更新虚表,会将原来指向...在调用的时候,根据类中虚指针定义的虚表所指向的函数进行调用虚函数,这就是继承的根本原理,虚函数则是面向对象最强大的武器。非虚函数就是普通的函数,不过前面加上了类作用域。...静态绑定与动态绑定:当new一个C类时,得到一个指针p(上图所示),当通过p调用vfunc1的时候,实际上是最下面中间语句进行调用的(其中n为编译器给虚函数在虚表中的索引),这是函数的调用方式与c很不一样...,在c的时代,当编译器看到函数调用,编译器会直接调用call XXX(XXX代表地址),地址是静态的,不会发生变化,这种方式叫做静态绑定,而C++通过类指针找到虚指针,根据虚指针找到虚表,从虚表中取出虚函数地址进行调用

    51320

    D语言的陷阱

    其中值得一提的是它的虚方法调用机制师从于Java。俺所说的是D在OOP上的理解。  现代编程语言基本都提供了OOP的编程机制,即封装,继承和多态。先声明一下,在这里我们讨论的主要是语言层面的OOP。...D语言采用单根+接口的继承机制。在多态上主要使用虚方法表和多接口来实现,而数据封装则主要通过它的attributes。  OK,下面我们先来看下D语言attributes语法层面上的小陷阱。 ...前面都好理解,但是连成员函数都默认是public,这就奇怪了。从OOP的角度来说,默认应该是保护级别的最大级别,尤其是在类中。在C++中,成员函数默认是private,这跟数据封装有关系。...在D中,private修饰的函数不仅可以被所在类的内部成员访问,甚至可以被同一模块内的其他成员访问。在同一模块内,它相当于C语言中被static修饰的函数,表达的是friend的语义。...但是在D中却不能编译通过。原因是B中并不存在有函数匹配Method()原型,所以b.Method()会调用不成功。奇怪,B明明继承父类A的Method()了啊。怎么会不能编译?

    66110

    C#中的override和new关键字

    如果对Java熟悉的朋友,可能会认为是结果: 这是父类方法 这是子类方法 但是其实运行结果是: 这是父类方法 这是父类方法 这是因为Java中的类方法默认是虚函数(虽然Java中没有这个叫法),子类函数会默认覆盖父类的同名函数...然而C#中必须使用virtual关键字显示声明该函数是虚函数,然后在子类中使用override关键字重写父类方法,这才真正实现了对父类方法的重写,才能实现多态(C++中的多态就是使用虚函数实现的,而且和...正确的结果是: 使用override关键字修饰的方法 这是一个虚方法 为什么使用关键字new修饰的方法,调用的是父类的方法呢? 是不是很奇怪?...例如,这意味着在基类中引入与派生类中的某个成员具有相同名称的新成员在 C# 中是完全支持的,不会导致意外行为。...它还意味着类必须显式声明某方法是要重写一个继承方法,还是一个隐藏具有类似名称的继承方法的新方法。 在 C# 中,派生类可以包含与基类方法同名的方法。 基类方法必须定义为 virtual。

    1.3K20

    【C++】多态 ⑬ ( 多继承中应用 “ 抽象类 “ | 接口和抽象类 | C++ 语言中接口实现 | 只定义 纯虚函数 的 抽象类作接口 | )

    + 语言 中 , 没有 接口 Interface 概念 , 只有 抽象类 AbstractClass 概念 ; 2、编程语言对接口和多继承的支持 大部分 面向对象语言 不支持 多继承 , 即使是 C...语言中接口实现 C++ 语言中 , 没有接口概念 , 这里使用 " 纯虚函数 " 实现接口 ; 接口类特点 : 接口类中 只有 函数原型 , 没有成员变量 , 函数原型 指的是 函数只有 返回值 函数名...和 参数列表 , 没有函数体 ; C++ 中的 接口类 有如下要求 : 类中只能定义纯虚函数 , 该类是一个抽象类 ; 类中不能定义除纯虚函数之外的其它成员 , 如 普通函数 , 成员变量 ; 下面的类就是...virtual void pureVirtualFunction() = 0; }; 二、代码示例 - 多继承中应用 " 抽象类 " 在 C++ 中 , 使用只定义了 纯虚函数 的 抽象类 ,...作为接口 ; 借助 C++ 多继承的特性 , 继承多个 " 只定义了 纯虚函数 的 抽象类 " , 也就是接口 ; 代码示例 : #include "iostream" using namespace

    23120

    VC和GCC成员函数指针实现的研究(三)

    接上一篇 VC和GCC内成员函数指针实现的研究(二) 虚继承 终于到最后的虚继承了。...*ptr)(); return 0; } VC虚继承成员函数指针实现 因为是兼容虚继承和非虚继承的,所以赋值的部分的汇编是一样的。这里就不贴了。关键在于执行期它是怎么找到虚基类的。...所以,在非第一个虚基类的函数指针调用时,VC用了一个和多继承相同的处理,即多一层vcall作地址偏移: image.png 图十六:VC多重虚继承的非第一个虚基类的地址偏移换算 也是因为虚基类的调用传入的...image.png 图十七:VC多重虚继承的取成员变量和虚基类成员变量 GCC虚继承成员函数指针实现 同样,赋值部分没什么特别的,和前面都一样。...由于1,这个转换过程中的offset值不知道了。所以必须要靠成员函数指针把这个offset存> 下来。

    82410

    C++ 多态

    多态概念 多态性是面向对象编程中的一个核心概念,它允许对象通过统一的接口表现出不同的行为。多态性增强了程序的灵活性和可扩展性。...这主要通过继承和虚函数来实现。 继承:允许一个类(子类或派生类)继承另一个类(基类或父类)的属性和方法。子类可以重写基类中的虚函数,从而在运行时表现出不同的行为。...虚函数:在基类中声明为virtual的成员函数。当通过基类指针或引用调用虚函数时,如果指针或引用实际上指向的是派生类对象,那么将调用派生类中重写的虚函数版本。...这种机制允许在运行时根据对象的实际类型来确定调用哪个版本的函数。 多态实现 多态需要继承关系,在继承关系下调用同一函数产生不同行为。...在C++11及以后的版本中,可以使用override关键字来显式指定重写基类虚函数,这有助于编译器检查重写是否正确。

    5810

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

    ③ 派生类中重写的虚函数可以不加 virtual(建议最好加上) 这里去掉子类重写的虚函数的 virtual 是可以的,但是注意不能去掉基类中虚函数的 virtual,因为它认为派生类是先继承父类的虚函数的...final :修饰虚函数,表示该虚函数或类不能再被继承 class Car { public: virtual void Drive() final {} //在不想被继承的函数之前加上final...,而 虚表指针是在构造函数初始化列表的时候产生的!这个下面会有实例解释。 覆盖就是指虚表中虚函数的覆盖。重写是语法的叫法,覆盖是原理层的叫法。...总结一下派生类的虚表生成: 先将基类中的虚表内容拷贝一份到派生类虚表中 如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后...多继承中的虚函数表 多继承中的虚表那就更复杂啦!

    1.2K30

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

    那么在继承中要 构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 2.虚函数 我们在讲继承的菱形继承的时候曾经说到过虚拟继承...,派生类的虚函数在不加  virtual 关键字时,虽然也可以构成重写 ( 因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性), 但是该种写法不是很规范,不建议这样使用 虚函数重写的两个例外...虚函数表本质是一个存虚函数指针的指针数组,一般情况这个数组最后面放了一个 nullptr 。(在VS中的情况) 5....总结一下派生类的虚表生成: a.先将基类中的虚表内容拷贝一份到派生类虚表中 b.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后...答:不能,因为对象中的虚函数表指针是在构造函数初始化列表 阶段才初始化的。 4. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?

    78450

    C# 继承和多态

    基类和派生类 一个类可以派生自多个类或接口,这意味着它可以从多个基类或接口继承数据和函数。...在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。 多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。...在 C# 中,每个类型都是多态的,因为包括用户定义类型在内的所有类型都继承自 Object。 静态多态性 在编译时,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。...当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法。 虚方法是使用关键字 virtual 声明的。 虚方法可以在不同的继承类中有不同的实现。 对虚方法的调用是在运行时发生的。...抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化; (2)抽象方法只能在抽象类中声明,虚方法不是; (3)派生类必须重写抽象类中的抽象方法,虚方法则不必要。

    67110

    【C++高阶】掌握C++多态:探索代码的动态之美

    多态的原理 虚函数表 在开始前先问大家一个 简单的 问题,下面这个类的大小是多少?在类和对象时,我们讲过类的大小判定和结构体差不多,那么在x86中,它的大小到底是不是4bytes?...最后派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后 注意虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是 他的指针又存到了虚表中。...虚函数表 单继承中的虚函数表 单继承中的虚函数表 class Base { public : virtual void func1() { cout<<"Base::func1" <<endl;}...((VFUNC*)(*((int*)&d))); return 0; } 注意:有的时候可能会莫名其妙多出很多函数指针,这时我们只需要清理以下解决方案即可 多继承中的虚函数表 多继承中的虚函数表...指针,无法访问虚函数表 构造函数不可以是虚函数,对象中的虚函数表指针是在构造函数阶段才初始化的,虚函数的多态调用要去虚函数表中找,但虚函数表指针还没初始化 5.

    33420
    领券