首页
学习
活动
专区
圈层
工具
发布

当我尝试调用函数时,_vfptr变为null

当你尝试调用函数时,_vfptr变为null,这通常是由于以下几种情况引起的:

  1. 对象未正确初始化:_vfptr是一个指向虚函数表的指针,它用于实现C++中的多态性。当一个对象被创建时,_vfptr会被初始化为指向该对象所属类的虚函数表。如果对象未正确初始化,_vfptr可能会被设置为null,导致调用函数时出现问题。
  2. 内存访问错误:_vfptr变为null也可能是由于内存访问错误导致的。例如,当你尝试访问已被释放或未分配的内存时,_vfptr可能会被破坏并变为null。
  3. 编译器或链接器错误:在某些情况下,编译器或链接器可能会出现错误,导致_vfptr变为null。这可能是由于编译器优化、链接错误或其他编译工具问题引起的。

针对这个问题,你可以采取以下步骤进行排查和解决:

  1. 检查对象初始化:确保你的对象在使用之前已经正确初始化。检查构造函数是否正确设置了_vfptr指针,并且没有发生任何错误导致其被设置为null。
  2. 检查内存访问错误:使用内存调试工具(如Valgrind)来检查是否存在内存访问错误。确保你的代码没有访问已释放或未分配的内存,这可能会破坏_vfptr指针。
  3. 检查编译器和链接器配置:确保你的编译器和链接器配置正确,并且没有发生任何错误。尝试重新编译和链接你的代码,确保没有出现任何警告或错误信息。

如果以上步骤都没有解决问题,你可以尝试以下方法进一步排查:

  1. 调试代码:使用调试器(如GDB)来跟踪代码执行过程,查看_vfptr变量在何处被设置为null。这可能有助于找到问题的根本原因。
  2. 检查函数调用:确保你的函数调用方式正确,并且没有发生任何错误。检查函数签名、参数传递和返回值等方面是否正确。

总结起来,当你尝试调用函数时,_vfptr变为null可能是由于对象未正确初始化、内存访问错误或编译器/链接器问题引起的。通过检查对象初始化、内存访问、编译器/链接器配置以及调试代码,你可以找到并解决这个问题。

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

相关·内容

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

那么在继承中要 构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 2.虚函数 我们在讲继承的菱形继承的时候曾经说到过虚拟继承...协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...但是当我们给父类析构函数加上 virtual 。析构的时候就会调用子类的析构函数了。这是因为不加 virtual 的时候,析构函数是普通调用,而加上了 virtual 之后就变成了多态调用。...而当我们用Student类对象调用的时候,派生类的内部会拷贝基类的虚表内容过来,但是由于我们已经重写了Person类虚表中的函数,所以调用的时候,我们找到的函数实现方法也已经发生了改变。...满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的。

87550

【C++深度探索】全面解析多态性机制(二)

//先定义一个函数指针类型 typedef void(*VFPTR) (); //打印函数指针数组中存放的函数地址 void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用...Func时: 当使用Student类对象调用函数Func时: 我们看到,p是指向Black对象时,p->BuyTicket在Black的虚表中找到虚函数是Person::BuyTicket。...我们发现不同的对象调用Func函数时,使用的虚函数表是不同的,Person类对象和Student类对象都使用各自的虚函数表,所以调用不同的虚函数,如下图所示: 这样就实现出了不同对象去完成同一行为时...那么当我们直接使用对象调用成员函数时走的是静态绑定,是指编译期间就确定的程序行为;当我们使用基类指针或引用调用虚函数时走的是动态绑定,需要通过虚函数表来确定不同对象调用不同的函数,根据具体拿到的类型确定程序的具体行为...,当派生类对基类的虚函数进行重写时,通过基类对象指针和引用调用虚函数时,就会通过虚函数表来确定不同对象调用不同的函数,根据具体拿到的类型确定程序的具体行为,所以多态实现的两个条件缺一不可。

17710
  • 【C++】———— 多态

    ,传递的是子类就调用子类的函数, 在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范...虚函数重写的两个例外: 2.1协变 派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指 针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。...因为这里发生了隐藏,~Person()变为 this->destructor() ~Student()为this->destructor() 编译器将他们两个的函数名都统一处理成了destructor...2.多态的原理 有了虚函数表的概念,我们可以尝试通过虚函数表,去找到多态的原理 下面是测试代码 class Person { public: virtual void BuyTicket()...,因此p的地址也是__vfptr的地址,那么我们通过__vfptr的地址就可以找到虚函数表里面的内容,因此我们在内存2里面输入__vfptr的地址,我们便找到了两个虚函数的地址。

    19810

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

    main() { Person* p1 = new Person; Person* p2 = new Student; delete p1; delete p2; return 0; } 当我们通过基类的指针来删除一个派生类的对象时...反思一下为什么 满足多态条件,这里的调用生成的指令就会指向对象的虚表中找对应的虚函数调用 满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。...之后调用 PrintVFT(ptr); 就可以遍历虚表中的每个条目并调用对应的函数(这里的函数都是通过函数指针 VFPTR 调用的) 3.抽象类 在虚函数的后面写上 =0 ,则这个函数为纯虚函数。...这意味着即使 B::func 定义了一个默认值 0,在 A::test 中调用 func() 时,由于它在编译时是视为 A 类型的函数调用,所以使用的是 A::func 定义的默认参数 1。...无论 B 和 C 在其构造函数中怎么尝试初始化 A,它们的尝试都会被忽略 根据上述规则,执行 new D("class A", "class B", "class C", "class D"); 的过程如下

    44700

    “虚函数表”推演及多态的原理

    使用VS调试一下我们可以看到,a对象中,多了一个成员,是_vfptr,如下图: 这是一个函数指针数组,里面包含了所有类中虚函数的指针。..._vfptr 的起始地址 cout vfptr address = “ << (int*)(*((int*)&a)) << endl; // 得到了虚函数表的起始地址后想调用表中的第一个函数...// 就需要对地址解引用,得出第一个函数的地址 *((int*)(*((int*)&a))) // 然后将其强制转换为一个函数指针,进行调用 cout vfptr...很明显我们发现,继承下来的类 A 中的虚函数表第一个函数变成了 B::func,实际上,这个操作只是将虚函数表中的函数指针进行了覆盖。这种方式我们就称为覆写。当你使用子类对象初始化一个父类的指针时。...这个指针在调用 func 函数时,会优先遍历虚函数表,如果发现同名函数,则调用之。如果没有发现再到非虚函数表以外的成员方法中寻找。

    19530

    【C++】继承和多态扩展学习

    但是这里引出一个问题是当我们通过父类指针访问子类对象,这是对于合并的部分,要如何确定位置呢?大家可能觉得合并的部分不是已经放在最后或者最上面了吗?...所以下面我们写了一份特殊代码,通过指针的方式,强制访问了虚函数表,调用了虚函数,确认继承中虚函数表中的真实内容。...)(); void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用。...,那么多态调用p2->func1()时,p2传递给this前需要把p2给修正回去指向Derive对象,因为func1是Derive重写的,里面this应该是指向Derive对象的。...对象访问普通函数快还是虚函数更快?答:首先如果是普通对象调用,是一样快的。如果是指针或者是引用对去调用,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。 9.

    10100

    【c++】多态(多态的概念及实现、虚函数重写、纯虚函数和抽象类、虚函数表、多态的实现过程)

    举个例子,当我们提到汽车、飞机、轮船等交通工具时,它们虽然都属于“交通工具”这一大类,但在实际使用时,却有着不同的出行方式。也就是说,当我们说“乘坐xx出行”时,这些交通工具会以各自独特的方式行驶。...这样,派生类的虚函数就提供了一个基类虚函数的新实现。然后我们调用该虚函数时,编译器就会根据基类的指针/引用所表示的对象类型来调用相应的虚函数。...但从运行结果中可以看出,这段代码出问题了:对于p1指针,它所指向的对象是A类型,对象销毁时直接调用A类型的析构函数,没毛病;但是对于p2指针,它所指向的对象是B类型,B是A的派生类,其在销毁时首先要调用派生类析构...(而不是根据指针),那么当p2指向的对象在销毁时,就会调用B的析构函数,进而在函数内部调用A的析构函数,完成派生类部分和基类部分的数据销毁。...我们通过基类的指针或引用调用虚函数时,若该指针或引用指向的是父类,运行时就到指向父类对象的虚函数表中找到对应的虚函数进行调用;若指向的是子类,运行时就到指向子类对象的虚函数表中找到对应的虚函数进行调用。

    74021

    C++:28 --- C++内存布局(上)

    C ++规范要求NULL指针在强制转化后依然为NULL ,因此在做强制转化需要的运算之前,VC++会检查指针是否为NULL。...因此,调用虚函数的过程如下:取得实例的vfptr;通过vfptr得到虚函数表的一项;通过虚函数表该项的函数地址间接调用虚函数。...也就是说,在普通函数调用的参数传递、调用、返回指令开销外,虚函数调用还需要额外的开销。 回头再看看P和Q的内存布局,可以发现,VC++编译器把隐藏的vfptr成员变量放在P和Q实例的开始处。...这就使虚函数的调用能够尽量快一些。实际上,VC++的实现方式是,保证任何有虚函数的类的第一项永远是vfptr。...这就可能要求在实例布局时,在基类前插入新的vfptr,或者要求在多重继承时,虽然在右边,然而有vfptr的基类放到左边没有vfptr的基类的前面(如下)。

    1.2K20

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

    举个例子:就拿刚刚结束的五一假期买票热为例,买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人买票时是优先买票。同样一个行为在不同的对象上就有不同的显现。...我们运行看看: 多态调用:运行时,到指定对象的虚表中找虚函数来调用(指向基类调用基类的虚函数,指向子类调用子类的虚函数) 普通调用:编译时,调用对象是哪个类型,就调用它的函数。...构成重写 那么我们就只需要将析构函数变为虚函数就可以了: class Person { public: virtual ~Person() { cout 函数时基类的指针,那么就会切片出来一个基类(虚函数表是派生类的),那么就会在派生类虚表调用对应虚函数。 这样就实现了执行谁就调用谁!!! 运行过程中去虚表中找对应的虚函数调用。...满足多态,那么运行时汇编指令会去指向对象的虚表中找对应虚函数进行调用!!! 不满足多态,编译链接时直接根据对象类型,确定调用的函数,确定地址!!!

    12910

    C++多态原理揭秘

    ,需要为虚函数,确保在析构父类指针时,能够正确调用其子类的析构函数 virtual ~Fruit() {} }; // 定义苹果类,继承自水果类 class Apple : public Fruit...(新增) 原理: 多态是因为在派生类中,对继承下来的虚函数进行了重写. 当程序调用一个虚函数时,实际上是通过对象的vptr找到相应的虚函数表,再根据函数在虚函数表中的索引找到具体的函数地址。...如果对象是派生类的实例,而且派生类中重写了虚函数,那么调用该函数时就会调用派生类中的版本。这种机制在程序运行时动态决定了具体调用哪个函数,从而实现了多态特性。...注意: 多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。...不满足多态的函数调用时编译时确认好的 简单来说就是,普通的函数调用就是 call这个函数的地址,然后执行函数的语句就行,这就是静态的调用.

    19220

    干货丨C++中的虚函数

    这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。...在WinXP+VS2003下,这个值是NULL。...这样,我们就可以看到对于下面这样的程序, Base *b = new Derive(); b->f(); 由b所指的内存中的虚函数表的f()的位置已经被Derive::f()函数地址所取代,于是在实际调用发生时...(关于这方面的尝试,通过阅读后面附录的代码,相信你可以做到这一点) 二、访问 non-public 的虚函数 另外,如果父类的虚函数是private或是protected的,但这些非public的虚函数同样会存在于虚函数表中...先来分析我们的main函数中的Derive类的对象obj,看看它的内存布局,由于没有数据成员,它的大小为4个字节,只有一个vfptr,所以obj的地址也就是vfptr的地址了。

    78941

    【C++】多态(下)

    函数调用时在A的虚表中找到func,当ra为B对象时,函数调用时在B的虚表中找到func,然后调用,这样就实现出了不同对象去完成同一行为时,展现出不同的形态 我们要达到多态,有两个条件,一个是虚函数覆盖...eax: 0038257B mov eax,dword ptr [edx] call eax中存虚函数的指针,这里可以看出满足多态的调用,不是在编译时确定的,是运行起来以后到对象的中取找的 对于普通调用...那我们如何查看整个b的虚表呢 typedef void(*VFPTR) (); void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用。...VFPTR,这是一个函数指针,指向的类型是void*,参数为(),也就是无参,也就是说这个指针可以指向任意一个返回类型为void*并且无参的函数 PrintVTable函数的参数也可以写成VFPTR*...最好把基类的析构函数定义为虚函数,因为如果基类的析构函数不是虚函数,那么只会调用基类的析构函数,而不会调用派生类的析构函数,这会导致派生类部分的对象没有被正确析构,可能会引发资源泄露 对象在访问虚函数与普通函数速度的对比

    14510

    初识C++ · 多态(1)

    所以现在可以得出多态实现的两个条件,第一个是必须通过基类的指针或者引用来调用虚函数, 第二个是调用的函数必须是虚函数,而且是在派生类中进行重写了的。 那么,什么是虚函数和重写?...第二种,我们将构造函数变为私有的,这样就可以防止类被继承了,因为派生类构造的时候也会调用基类的构造,这里变为私有的就构造不了了,这种方法的思路挺厉害的: class A { private: A()...因为这里面还是一个虚函数表指针,即大小为8,相加13,但是要满足是8的倍数,所以大小就是16。 什么?哪里来的虚函数表指针? _vfptr就是虚函数表指针,这是在监视窗口看得到的。...Student是一样的,就不调试了,我们再来看一眼汇编: 满足多态就会生成这么一大堆指令,在运行的时候确定应该调用谁的函数,如果不满足多态,就是这样,在编译的时候就确定了调用谁的函数: 直接就选择调用了...>", vft[i]); VFPTR pf = vft[i]; (*pf)(); } } int main() { Base b1; Drive d1; VFPTR* ptr = (VFPTR

    13710

    移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——11.多态

    举个栗子:比如买票这个行为,当普通人买票时,是全价买票;学生买票时,是半价买票;军人 买票时是优先买票。  2. 多态的定义及实现 2.1多态的构成条件 在继承中要构成多态还有两个条件: 1....必须通过基类的指针或者引用调用虚函数 2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 2.2 虚函数  虚函数:即被virtual修饰的类成员函数称为虚函数。...Person的析构函数,下面的delete对象调用析构函 数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。...typedef void(*VFPTR) (); void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用。...如果是指针 对象或者是引用对象,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函 数表中去查找。 9. 虚函数表是在什么阶段生成的,存在哪的?

    16910

    多态与虚(函数)表

    那么在继承中要构成多态还有两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 1. 2️⃣虚函数 虚函数:即被virtual修饰的类成员函数称为虚函数...Person的析构函数,下面的delete对象调用析构函 数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。...再通过下面的汇编代码分析,看出满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的。...这里可以看出满足多态的调用,不是在编译时确定的,是运行起来 以后到对象的中取找的。...下面我们使用代码打印 出虚表中的函数 typedef void(*VFPTR) (); void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用。

    65320

    C++之多态

    4.虚函数重写的两个例外 协和: 派生类重写基类虚函数时,与基类虚函数返回值类型不同。...Func得到不同的结果,这是因为基类调用函数的传参基类对象,而派生类对象调用函数时的传参是派生类对象中基类的那一部分。...导致基类的指针p是调用基类的成员函数,派生类的指针p是调用派生类的成员函数。 简单来说: 普通函数调用是传谁调用谁; 符合多态的函数调用就是指向谁调用谁。...满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的(动态绑定);不满足多态的函数调用是在编译时就确定的(静态绑定)。...) ();//函数指针 void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用。

    41940

    多态的讲解

    但是要满足多态在继承中就要有以下两个条件: 必须通过基类的指针或者引用调用虚函数 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写 如果是对象直接调用的话就不会构成多态,上图中的虚函数覆盖就是我们所说的虚函数重写...,这就是多态的体现,如果是学生就是半票,不是学生就是全票 另外大家要注意: 在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性...: 协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数时,与基类虚函数返回值类型不同。...再通过下面的汇编代码分析,看出满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的。...) (); void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用。

    13310
    领券