c++ 未初始化的对象指针调用虚函数导致流程错误,为什么?

fly2sky 2009-10-25 04:44:56
未初始化的对象指针调用虚函数时会导致流程错误,而未初始化的对象指针调用非虚构函数却可以,这是为什么呢?
我验证过了,真的是这样,这是为什么啊!
class A
{
public:
virtual void vfun()
{
cout<<"A::vfun()"<<endl;
}
void fun()
{
cout<<"A::fun()"<<endl;
}
};
int main(int argc, char* argv[])
{
A *pa;
pa->fun();
//pa->vfun(); //这句导致流程错误,上边一句没事
return 0;
}
...全文
395 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
test_machine 2009-11-13
  • 打赏
  • 举报
回复
这个问题我也遇到了,我从CStdioFile派生一个类,在OPEN时出错,就是熟知的0x000005,跟踪后就是虚函数表指针错误;令人郁闷的时,我在对象时创建时(构造函数)中可以明确看基类CFile和CStdioFile的虚函数表,完成时也能看派生类的虚函数指针,但是调用时却没有了!正在找为什么会这样!
laironggui 2009-10-27
  • 打赏
  • 举报
回复
月子,哥来作答吧!
我是这么理解的,一个类若有虚函数的话,那么该类必然会创建一个V表,v表的作用就是保存自己类中虚函数的地址,我们可以把v表形象地看成一个数组,这个数组的每个元素存放的就是虚函数的地址。要调用虚函数,首先是取出指针vptr的值,这个值就是v表中的地址,再根据这个值来到v表这里,调用虚函数。若未初始化,就没有V表,所以指针无处可指。
而非虚函数仅是直接跳转到函数的代码处
laironggui 2009-10-27
  • 打赏
  • 举报
回复
月子,我才发现,这个问题你贴到这来了!呵呵~
fly2sky 2009-10-26
  • 打赏
  • 举报
回复
真的没人回复了么,我觉得二楼大哥说的挺有道理的~
angel_su 2009-10-26
  • 打赏
  • 举报
回复
lz可以试试暴力呼叫:
pa->A::vfun()

含有虚函数的类,头部会多一个指针,编译器不会依据类型直接呼叫函数,而是根据这个多出来的指针,跳到虚函数表某部位,再转跳到实际函数,这样就实现动态连接。不过现在没建立实例对象,不可能找到真正函数入口,乱跳的结果就是挂掉。

至于成员函数和普通函数主要差别在是多传了个this指针,因为你不操作任何类成员,所以正常不出事,但实际应用不大可能有这么侥幸的情况。
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 thy38 的回复:]
编译器会为类声明一个trivial默认构造函数,一个trivial析构函数,一个trivial拷贝构造函数,一个trivial拷贝赋值运算符,取址运算符及其const版六个成员函数。非虚函数的指针不会改变,所以类定义之后就有了其地址的映射方式。

所以这里pa->fun()会先调用默认的取址运算符,通过类地址找到fun函数的地址,并调用它。

而虚函数的地址要查表得到,而此时虚表尚未构造,所以出错。
[/Quote]


不懂就别瞎说!
虚函数表只有在声明了类对象之后才会有,而上面的问题,根本没给pa分配空间,所以,根本无所谓fun或者vfun,建议你看看 深度探索c++对象模型,以后不明白的地方,请不要误人子弟


程序明显运行崩溃,因为你没有给pa分配空间,
如果声明为 A pa;
那样的话会调用默认构造函数,vs2008编译~~
fly2sky 2009-10-26
  • 打赏
  • 举报
回复
我们的讨论有些偏题了,重点放在调用虚函数为什么异常那部分~~~~
fly2sky 2009-10-26
  • 打赏
  • 举报
回复
没人回复了么,嘿嘿,还期待着精彩的解答呢~~
太乙 2009-10-25
  • 打赏
  • 举报
回复
从未见过!!!
cba_v 2009-10-25
  • 打赏
  • 举报
回复
up
fly2sky 2009-10-25
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 mstlq 的回复:]
C/C++ codeusingnamespace std;class A
{public:
A(){data=newint[99999];}virtual~A(){delete [] data;}virtualvoid vfun()
{
cout<<"A::vfun()"<<endl;
}void fun()
{
data[88888¡­
[/Quote]
我明白你这个意思,嘿嘿,就是没有初始化的时候就不会调用构造函数,data数组就还没有开辟内存地址,这个时候给data[8888]赋值肯定会崩溃的,不过你这个例子举得很好,谢谢了~
mstlq 2009-10-25
  • 打赏
  • 举报
回复



using namespace std;
class A
{
public:
A(){data=new int[99999];}
virtual ~A(){delete [] data;}
virtual void vfun()
{
cout <<"A::vfun()" <<endl;
}
void fun()
{
data[88888]=888;
cout <<"A::fun()" <<endl;
}
private:
int *data;
};
int main(int argc, char* argv[])
{
A *pa;
pa->fun(); //期待着看楼主的结果^_^
return 0;
}
fly2sky 2009-10-25
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 loaden 的回复:]
A *pa;
pa->fun();
能访问,并不代表正确,编译器也不保证正确!
这是编译器内部实现,不必细究。
正常情况应该是崩溃!
[/Quote]
这个不崩溃的,我刚才试过了~
老邓 2009-10-25
  • 打赏
  • 举报
回复
A *pa;
pa->fun();

能访问,并不代表正确,编译器也不保证正确!
这是编译器内部实现,不必细究。
正常情况应该是崩溃!
fly2sky 2009-10-25
  • 打赏
  • 举报
回复
fun中访问成员变量没事,我刚才试了试!
thy38 2009-10-25
  • 打赏
  • 举报
回复
编译器会为类声明一个trivial默认构造函数,一个trivial析构函数,一个trivial拷贝构造函数,一个trivial拷贝赋值运算符,取址运算符及其const版六个成员函数。非虚函数的指针不会改变,所以类定义之后就有了其地址的映射方式。

所以这里pa->fun()会先调用默认的取址运算符,通过类地址找到fun函数的地址,并调用它。

而虚函数的地址要查表得到,而此时虚表尚未构造,所以出错。
  • 打赏
  • 举报
回复
你在fun里面访问一下成员变量试试。

64,642

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧