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

当我尝试调用函数时,_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类虚表中的函数,所以调用的时候,我们找到的函数实现方法也已经发生了改变。...满足多态以后的函数调用,不是在编译确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译确认好的。

72150

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

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

3410

【C++】———— 多态

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

8810

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

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

13530

【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"); 的过程如下

18200

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

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

7510

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

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

1K20

干货丨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的地址了。

56441

C++多态原理揭秘

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

13420

【C++】多态

举个栗子:比如买票这个行为,当普通人买票,是全价买票;学生买票,是半价买票;军人买票是优先买票。...虚函数重写的两个例外: 协变(基类与派生类虚函数返回值类型不同) 派生类重写基类虚函数,与基类虚函数返回值类型不同。...最终达到的目的就是执行谁调用谁,运行去虚表中找对应的虚函数调用,指向父类调用父类的虚函数,指向子类调用子类的虚函数。 p中存的是mike对象的指针,将p移动到eax中。...这里可以看出满足多态的调用,不是在编译确定的,是运行起来以后到对象的中取找的。...(VFPTR*)(*((int*)&d)); PrintVFT(ptr); // 函数指针 void (*p1)(); VFPTR p2; // 函数指针数组 void (*pa1[10

7610

什么是多态?如何实现?只看这一篇就够了

那么在继承中要构成多态还有两个条件: 必须通过基类的指针或者引用调用函数调用函数必须是虚函数,且派生类必须对基类的虚函数进行重写 ?...: 协变(基类与派生类虚函数返回值类型不同)派生类重写基类虚函数,与基类虚函数返回值类型不同。...反过来思考我们要达到多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调用函数。 满足多态以后的函数调用,不是在编译确定的,是运行起来以后到对象的中去找的。...不满足多态的函数调用时编译确认好的。 ?...typedef void(*VFPTR) (); void PrintVTable(VFPTR vTable[]) { // 依次取虚表中的虚函数指针打印并调用

1.3K10

多态与虚(函数)表

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

56320

多态的讲解

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

5710

C++之多态

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

33540

【C++航海王:追寻罗杰的编程之路】多态你了解多少?

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

7610

HotSpot源码分析之C++对象的内存布局

而C++实现动态分派主要就是通过虚函数来完成的,非虚函数在编译就已经确定调用目标。C++中的虚函数通过关键字virtual来声明,如上函数func()没有virtual关键字,所以是非虚函数。  ...]; 另外我们还可以看到,虚函数指针vfptr位于所有的成员变量之前。 ...| {vfptr} 1> 8 | base1_var1 1> 12 | base1_var2 1> +--- 可以看到,内存布局无论有一个还是多个虚函数都是一样的,改变的只是vfptr指向的虚函数表中的项...所以当调用Derive1对象的base1_fun1()函数,会根据虚函数表找到Derive1::base1_fun1()函数进行调用,而当调用Base1对象的base1_fun1()函数,由于Base1...对象的虚函数表中的vtable[0]指针指向Base1::base1_func1()函数,所以会调用Base1::base1_fun1()函数

53720

函数与虚继承寻踪

virtual在C++中最大的功能就是声明虚函数和虚基类,有了这种机制,C++对象的机制究竟发生了怎样的变化,让我们一起探寻之。 为了查看对象的结构模型,我们需要在编译器配置做一些初始化。...adjust表示虚函数机制执行时,this指针的调整量,假如fun被多态调用的话,那么它的形式如下: *(this+0)[0]() 总结虚函数调用形式,应该是: *(this指针+调整量)[虚函数在vftable...假设我们使用如下语句: MyClass*pc=new MyClassA; pc->fun(); 编译器在处理第二条语句,发现这是一个多态的调用,那么就会按照上边我们对虚函数的多态访问机制调用函数fun...*(pc+0)[0]() 因为虚函数表内的函数地址已经被子类重写的fun函数地址覆盖了,因此该处调用函数正是MyClassA::fun,而不是基类的MyClass::fun。...如果使用MyClassA对象直接访问fun,则不会出发多态机制,因为这个函数调用在编译时期是可以确定的,编译器只需要直接调用MyClassA::fun即可。

86090
领券