分析C++方式构造函数调用虚函数的问题

c++ 纯虚函数被调用 错误原因 问题描述 最近写程序时,做了一个基类供其他模块调用,调试时出现了下面的错误: pure virtual method called 如图所示: 纯虚函数被调用。纯虚函数是需要子类具体实现的函数,怎么就被调用了呢? 首先明确观点:永远不要在构造和析构中直接/间接调用virtual函数。 下面是根据查阅的资料和自己的理解作出的解释,供参考。 抽象类和纯虚函数 来复习一下c++中的纯虚函数和抽象... 阅读详情

最近在看JAVA,因为JAVA是运行期绑定,所以里面提到了一个有趣的问题,就是在构造函数里面运行虚函数的问题。

 

构造函数里可以运行虚函数吗?我们先不讨论实际项目中是否有这个必要(至少我还没碰到过,也许即便碰到了也有其他的解决办法。),单就构造函数里调用虚拟函数的情况来做些分析。

 

在JAVA中,如果在构造函数中调用虚拟函数的话,是可以编译通过的,也不会出现运行期错误,但他的运行结果也许不是你想要的。在JAVA当中,由于是运行期绑定,而构造函数执行的虚拟函数将是衍生类中的函数(假如衍生类对该虚拟函数进行了覆盖的话),但这里我们会有疑问了,构造函数是从父类开始构建的,也就是此时衍生类还未构造出来,所以如果此时执行衍生类的函数无疑是不安全的。所以JAVA中的做法不能说没有问题的。

 

那么在VC++当中情形会一样吗?我很好奇,所以做了测试。

 

首先,我们使用如下代码测试:

 

以上代码运行结果如下:

 

从中我们可以看到,在VC++的实现方法和JAVA是不同的,在构造对象a时,虽然该对象是VirClassB类型,但在父类VirClassA构造函数中虽然调用的是虚拟函数,而且该虚拟函数被VirClassB覆盖了,但实际调用的还是VirClassA中的FunA,这个从道理上也说得过去,因为虽然最终要构造的对象是属于VirClassB的,但在此时此刻,它还属于VirClassA,所以调用的是VirClassA的FunA也合情合理。这当然比JAVA的做法更科学一些,至少不会出现JAVA中的莫名其妙的错误了。

 

当构建全部完成后,虚函数的执行恢复了正常,这从后面两个执行结果都是VirClassB FunA,可以看出来.

 

其实看源代码可以发现,其实虚函数表的指针赋值是发生在构造函数当中,且在构造函数执行之前,所以就不难解释上面的结果了。

 

但我还不想就此打住,因为我们不要忽视了另一个情况,就是纯虚函数。请看下面的代码:

 

我们将VirClassA的代码FunA修改为纯虚函数,并在VirClassA构造函数中调用,这在程序编写按理也是可以的吧?因为纯虚函数本来就是供衍生类覆盖的,在父类中调用也说得过去的。那么我们开始编译运行看看。

 

哦?~!出现了编译错误。

无法解析的外部符号 "public: virtual void __thiscall VirClassA::FunA(void)" (?FunA@VirClassA@@UAEXXZ) ,该符号在函数 "public: __thiscall VirClassA::VirClassA(void)" (??0VirClassA@@QAE@XZ) 中被引用

 

哇!不禁要惊叹编译器的聪明!因为构造函数中调用的将是VirClassA中的FunA,这在前面已经说过。你既然没定义,那么理应给一个编译错误,到这里VC++编译器还是值得我们信赖的。

 

那么再来一个测试例子。

 

大家可以测试下这个例子,看看出现了什么情况?没错,程序将当掉。

出现了运行期错误:

 

可以看到在FunA中调用一个纯虚函数FunB()时当掉了。将出现一个纯虚函数调用运行时错误。

 

所以编译器是没法识别绕了弯的构造函数里做纯虚函数调用。不过好在还有一个运行时错误,还是比JAVA高明一些。因为我们知道JAVA那种方式将出现一些很难识别的错误。

 

所以通过以上分析,大家最好还是不要在构造函数里调用虚函数,而且程序大师都是建议构造函数做尽可能简单的事情。相对于JAVA来说,VC++的做法应该是更安全的。

C++ 虚函数 C++ 中有关虚函数的一系列知识。 阅读详情

相关推荐

C++虚函数的访问方式

C++虚函数访问 本文讨论C++虚函数的访问方式。在文章最后会进行总结。(若有错误,请指正) 抛出问题:下图中为何不能够调用FuncB()函数而引发进而分析 1.分析如下: #include <iostream> using namespace std; class A { public: A(int a = 10) {} void FuncA() { cout <&l...

weixin_42795268的博客 933

C++中构造函数中调用虚函数的问题

C++中构造函数中调用虚函数的问题 在构造函数中调用虚成员函数,虽然这是个不很常用的技术,但研究一下可以加深对虚函数机制及对象构造过程的理解。这个问题也和一般直观上的认识有所差异。先看看下面的两个类定义。 struct C180 {  C180() {   foo();   this->foo();  }  virtual f

蜗牛不会飞 1034

基于STM32和MPU6050的手势控制小车设计与实现

MPU6050传感器:用于检测手势变化,采集加速度和陀螺仪数据。STM32微控制器:处理MPU6050传感器的数据,根据手势变化控制小车的运动。电机驱动模块:接收来自STM32的控制信号,驱动小车的电机,实现小车的前进、后退、左转和右转。小车底盘:作为整个系统的机械部分,提供移动平台。MPU6050是一款集成了3轴加速度计和3轴陀螺仪的传感器,具有高精度、低功耗和小体积等特点。它通过I2C接口与微控制器通信,可以实时采集加速度和角速度数据,广泛应用于运动检测、姿态控制和手势识别等领域。

m0_57781768的博客 2309

C++构造函数和析构函数中调用虚拟函数

C++ 析构函数 构造器 虚拟函数

lk_HIT的博客 2180

永磁同步电机矢量控制——电流内环前馈解耦策略

在采用永磁同步电机矢量控制时,ud和uq的指令值存在耦合项。需要对其进行解耦,目前,常用的解耦设计方法有前馈解耦、偏差解耦以及内模控制,本文主要分享电流内环前馈解耦控制策略。

a12312341ll的博客 8691

从ADS到HFSS:耦合线带通滤波器的设计与模型转换实战

本文详细介绍了耦合线带通滤波器的完整设计流程,重点阐述了从ADS电路级快速优化到HFSS三维电磁场精确验证的模型转换实战方法。通过对比ADS理想模型仿真与HFSS全波仿真结果,指导读者进行参数校准与迭代优化,并分享了关键的板材选择、加工误差及端口设置等避坑指南,确保设计性能与实物测试高度一致。

weixin_29290863的博客 344

在构造函数中调用虚函数

#include <iostream> using namespace std; class A { public: A() { this->fun(); } virtual void fun() { cout << "A fun" << endl; } }; class B :public A { public: B() { t...

Likes的博客 7993

液态神经网络(Liquid Neural Networks)从线虫大脑到下一代 AI

液态神经网络(Liquid Neural Networks,LNN)是一类具有动态内部结构的神经网络,其灵感来源于生物神经系统,尤其是大脑中神经元如何以复杂、非线性的方式响应外部刺激。与传统神经网络不同,液态神经网络的每个神经元在处理输入时,不再是静态线性或非线性变换,而是基于一个微分方程模型进行响应。这种建模方式使神经元的行为具有时间连续性和动态适应性。换句话说,它不仅“记住”过去的信息,还能根据当前环境实时调整自身的动态特性,这对于感知、决策、预测等任务都非常关键。

hello.reader 7410

C++ 构造函数与析构函数调用虚函数的注意事项

虽然可以对虚函数进行实调用,但程序员编写虚函数的本意应该是实现动态联编。在构造函数中调用虚函数,函数的入口地址是在编译时静态确定的,并未实现虚调用。但是为什么在构造函数中调用虚函数,实际上没有发生动态联编呢?第一个原因,在概念上,构造函数的工作是为对象进行初始化。在构造函数完成之前,被构造的对象被认为“未完全生成”。当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数,那么此时派生类的构造函数并未执行,所调用的函数可能操作还没有被初始化的成员,将导致灾难的发生。

Doublelv 的博客专栏。 1万+

yolov26改进 | Neck篇 | 利用Gold-YOLO改进yolov26对小目标检测能力(全网独家首发)

本文介绍利用Gold-YOLO的Neck改进YOLOv26,通过信息聚集—分发机制GD,先全局汇聚不同层级特征,再将融合后的全局信息重新注入各尺度分支,增强浅层细节与深层语义之间的交互,减少传统Neck逐层传递造成的信息损失。该结构虽然融合路径更长,但能够在不过度增加延迟的前提下提升多尺度目标检测能力,尤其适合大小目标并存、尺度变化明显和复杂背景场景。本文将讲解GD机制、Neck替换、模块注册与配置方法,并提供完整代码、配置文件及Codex修改思路,方便直接复现、实验对比和二次创新。

Snu77的博客 293

YOLO26涨点改进 | 检测头改进篇 | 利用ASFF改进YOLO26检测头,自适应空间特征融合模块,在所有的目标检测上均有大幅度的涨点效果

本文提出了一种自适应空间特征融合(ASFF)检测头YOLO26,用于解决目标检测中特征金字塔跨尺度特征不一致的问题。ASFF通过学习空间权重图,自适应地融合不同尺度的特征,抑制特征层间的冲突信息。实验表明,该方法在MSCOCO数据集上显著提升了检测精度(45FPS下AP达42.4%),且仅引入极小推理开销。ASFF模块具有可微分性、模型无关性和计算成本低等优势,能够有效改善特征尺度不变性,实现速度与精度的良好平衡。文章详细介绍了ASFF的原理、实现代码及其在YOLO模型中的集成方法。

Ai缝合怪、助力小伙伴高效发论文 551

C++ 构造函数和析构函数中调用虚函数的问题

C++构造函数和析构函数中调用虚函数效果与原因分析。

noevil的博客 1540

存储硬盘格式怎么把512还原为520格式??

硬盘厂商工具(如SeaChestsg_format)可以调整扇区大小。备份数据,因为调整扇区会清除硬盘内容。根据硬盘型号和接口类型,选择合适的工具进行调整。如果你需要更详细的帮助,请提供你的硬盘型号和存储设备类型。希望如上措施及解决方案能够帮到有需要的你。PS:如若遇到采纳如下方案还是未解决的同学,希望不要抱怨&&急躁,毕竟影响因素众多,我写出来也是希望能够尽最大努力帮助到同类似问题的小伙伴,即把你未解决或者产生新Bug黏贴在评论区,我们大家一起来努力,一起帮你看看,可以不咯。

**My Coding Family** 1146

[转载]分析C++方式构造函数调用虚函数的问题

在JAVA中,如果在构造函数中调用虚拟函数的话,是可以编译通过的,也不会出现运行期错误,但他的运行结果也许不是你想要的。在JAVA当中,由于是运行期绑定,而构造函数执行的虚拟函数将是衍生类中的函数(假如衍生类对该虚拟函数进行了覆盖的话),但这里我们会有疑问了,构造函数是从父类开始构建的,也就是此时衍生类还未构造出来,所以如果此时执行衍生类的函数无疑是不安全的。所以JAVA中的做法不能说没有问题的。

liocveeI的专栏 559

innovus:像ICC2一样设置placement label

ICC2有placement label/placement rule功能,能控制各种类型cell 之间的spacing规则,包括top和bottom edge的spacing。innovus也有相同的功能,以下示例方便大家了解用法。我们需要给所有OAI* cell之间设置一个spacing rule,让他们不要上下或者挨着。效果如下图,这个spacing指的是同一边的间距,不是cell间距。我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?

m0_61544122的博客 833

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

5 C++ 类和对象之构造函数

本文介绍了C++类的5种默认成员函数,重点阐述了构造函数、析构函数和拷贝构造函数的特性与使用注意事项。构造函数用于初始化对象,支持重载但需注意默认构造函数的存在规则;析构函数自动调用进行资源清理,不可重载且抽象类应设为虚函数;拷贝构造函数实现对象复制,需注意参数传递方式及浅拷贝问题。文中通过代码示例说明了这些函数的正确使用方式,并强调了在多态和资源管理场景下的关键设计要点。

2301_76755408的博客 807

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

C++静态联编和动态联编

在构造函数、拷贝构造函数或者析构函数中调用虚函数,一定是调用本类的虚函数,如果本类没有重写虚函数,则调用基类的虚函数。在构造、拷贝构造、析构函数中调用虚函数时编译器一律采用静态联编的方式,而不使用动态联编。

dyyfyyds_的博客 956

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++基础复习笔记(二)

1.()括号运算符的重载: class A{ public: int operator (int a, int b) { return a*a+b*b; } int sumfunction(int a,int b) { return a+b; } } int main() { A(2,3); A.sumfunction(2,3);//区别 } 2.纯...

nospeakmoreact的博客 120

菱形继承(及其深度探讨)

菱形继承(及其深度探讨) 普通的多继承 代码示例 #include<iostream> using namespace std; class object{ int value; public: object(int x = 0):value(x){} } class base:public object{ int num; public: base(int x = 0):num(x),object(x+10){} } class moude:public o

Nwk0000000001的博客 702

C++对象模型——构造,解构,拷贝语意学(第五章)

第5章 构造,解构,拷贝语意学 (Semantics of Construction, Destruction, and Copy) 考虑下面这个abstract base class 声明: class Abstract_base { public: virtual ~Abstract_base() = 0; virtual void interface() const = 0; vi

yiranant的专栏 782

C++继承中虚函数调用时机问题及解决方案

本文探讨了C++继承中虚函数在构造函数调用的时机问题及解决方案。通过设备管理案例,分析基类构造函数调用虚函数时派生类重写可能失效的问题,提出采用模板方法模式结合延迟调用的优雅解决方案。具体实现包括:1) 在基类中使用QTimer延迟调用虚函数;2) 通过虚函数getFilterList()让派生类提供自定义过滤列表;3) 避免在构造函数中直接调用虚函数。这种方法确保了对象完全构造后虚函数机制正常工作,解决了继承体系中初始化顺序导致的虚函数调用问题。

qq_41898196的博客 1109

咱们一起学C++ 第二百六十六篇之C++构造函数的调用规则与虚函数在其中的特殊表现

大家好!C++作为一门强大的编程语言,构造函数和虚函数是其中非常重要的概念。今天咱们就来深入探讨一下构造函数的调用规则,以及虚函数在构造函数中的特殊行为,希望通过这次学习,大家都能有所收获,咱们一起进步!

wj_rdk的博客 1503

构造函数 中调用虚函数的问题

1 #include <iostream> 2 using namespace std; 3 4 struct C180 5 { 6 C180() { 7 foo(); 8 this->foo(); 9 } 10 virtual void foo() { 11 co...

weixin_30691871的博客 188

c++构造函数,虚函数相关问题

1.c++中内存分布的特点: 全局区(静态区):全局变量,static修饰的局部变量和全局变量,编译时期已经确定 常量区:const修饰的全局变量(const修饰的局部变量还是存储在栈区)和一般的常量(比如字符串),虚函数表(编译时期已经确定下来) 代码区:static修饰的成员函数,一般的成员函数,代码,编译时期已经确定 一般的成员变量和虚函数指针一般是分配在堆或栈中。 一般const...

chengchaonan的博客 1433

C++构造函数中慎用虚函数

C++构造函数中慎用虚函数

xie__jin__cheng的博客 784

摘:C++中构造函数和析构函数避免调用虚函数的问题

http://anwj336.blog.163.com/blog/static/8941520920106791516915/ 一、构造函数避免调用虚函数的问题 在构造函数中调用虚成员函数,虽然这是个不很常用的技术,但研究一下可以加深对虚函数机制及对象构造过程的理解。这个问题也和一般直观上的认识有所差异。先看看下面的两个类定义。 struct C180{ C180() {  foo...

acass424022的博客 152
上一篇: 金山卫士界面源码解读及界面库分离(附录) --你问我答
下一篇: 金山卫士界面库界面编辑器效果图
b2b160
博客等级 码龄20年 2408粉丝 96原创
评论 42
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

b2b160

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值