发现虚函数表指针只对堆上创建的对象起作用。

luuillu 2011-08-26 04:57:34
多态对象在调用虚函数时,先跟据虚函数表指针得到虚函数表的地址,然后从虚函数表中找到对应的虚函数的地址,然后调用这个虚函数。因此虚函数是间接被调用的。

我原以为上面是正确的,但今天实际测试一下发现只对堆上创建的对象成立,对于栈上创建的对象,静态对象,以及全局对象,虚函数是被直接调用的,而不使用虚函数表指针。另外使用类型强制转换时虚函数是间接调用的.

测试环境 vs2010.

#include <iostream>

using namespace std;

class A
{
public:
virtual void f()
{
cout<<"A"<<endl;
}
};
class B: public A
{
public:
virtual void f()
{
cout<<"B"<<endl;
}
};
A a_g; //全局对象
int main()
{
static A a_s; //静态对象
A a_l; //局部对象
B b;

*(void **)(&a_g) = *(void**)(&b); //改变虚函数表指针
*(void **)(&a_s) = *(void**)(&b);
*(void **)(&a_l) = *(void**)(&b);

a_g.f(); //输出A
a_s.f(); //输出A
a_l.f(); //输出A

A &a_h = *(new A); //堆对象
*(void **)(&a_h) = *(void**)(&b);
a_h.f(); //输出B

(static_cast<B&>(a_l)).f(); //输出B

A a_r; //不改变虚函数表指针.
(static_cast<B&>(a_r)).f(); //输出A


}



...全文
298 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
cswuyg 2011-08-27
  • 打赏
  • 举报
回复
引用、指针调用虚函数。
点操作符调用虚函数。
luuillu 2011-08-27
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 lyntion 的回复:]

对象是如何转换为指针的,这种强制转……
[/Quote]
*(void **)(&a_g) 这里面有一个取地址操作符,因此是地址转成了指针,而不是对象转换成了指针。
  • 打赏
  • 举报
回复
学习了,不过这句我不理解
*(void **)(&a_g) = *(void**)(&b);  //改变虚函数表指针
*(void **)(&a_s) = *(void**)(&b);
*(void **)(&a_l) = *(void**)(&b);

对象是如何转换为指针的,这种强制转换不理解,请教请教
luuillu 2011-08-26
  • 打赏
  • 举报
回复
感谢各位的热心回复。 我明白了。

我原来理解错了,是否动态绑定与对象在堆上还是栈上创建无关,正如10楼所说的,是由多态的基本条件决定的。

多态的三个必要条件:
1.存在继承2.虚方法重写3.父类(指针或者引用)指向子类对象

根据条件3可知,只有通过对象的指针或引用调用虚函数才会引起动态绑定,直接通过对象调用虚函数是静态绑定。
gykgod 2011-08-26
  • 打赏
  • 举报
回复
A 有自己的虚表 B继承A B也有自己的虚表

这时候把A的虚表换成B的

然后测试多态
gykgod 2011-08-26
  • 打赏
  • 举报
回复
你们这帮人啊,LZ说的很清楚了

*(void **)(&a_g) = *(void**)(&b); //改变虚函数表指针

这个改变了虚表的地址,你们测试的前提是改变虚表地址,也就是vptr的内容

OK ???
cxyOOOO 2011-08-26
  • 打赏
  • 举报
回复
试试这个。

void foo_1(A& a)
{
B b1;
a.f();
b1.f();
}

void foo()
{
B b0;
foo_1(b0);
}

foo();
liufang421 2011-08-26
  • 打赏
  • 举报
回复
说错了
只有
A a;
a.func();
或者
A::func();
两种情况是编译的时候确定的,其他任何情况都是要查表的;

查不查表只跟以上两条有关,跟对象在堆还是在栈无任何关系,比如:
B b;
A *pa;
pa = &b;
pa->func();
(*pa).func();
以上两种都是要查表的,
想不查表则把func()换成A::func()
这样会强制把b的this传给A::func(),然后A::func()以A的方式访问b不安全;
pathuang68 2011-08-26
  • 打赏
  • 举报
回复
请楼主解释下面代码的运行结果:

#include <iostream>
using namespace std;

class A
{
public:
virtual void fun()
{
cout << "A's fun()" << endl;
}
};

class B : public A
{
public:
void fun()
{
cout << "B's fun()" << endl;
}
};

int main(void)
{
A a;
B b;
a.fun();
b.fun();
((A)b).fun();
((A*)&b)->fun();

return 0;
}
nightkids_008 2011-08-26
  • 打赏
  • 举报
回复
楼主纠结的地方超越了基本条件
liufang421 2011-08-26
  • 打赏
  • 举报
回复
用点访问相当于加上classname::编译的时候就确定了访问的函数
yby4769250 2011-08-26
  • 打赏
  • 举报
回复
扯蛋吧,看如下代码

class A
{
public:
virtual void v_f(){ cout<<"this is A"<<endl; }
};
class B:public A
{
public:
virtual void v_f(){ cout<<"this is B"<<endl; }
void m_f(){ cout<<"this is B's member func"<<endl; }
};

A* pa_g;
B* pb_g;

int main(int argc, char **argv)
{
A* pa_l;
B* pb_l;

pb_l->m_f(); //调用一般成员函数,函数寻址不需要对象,只要类型
pb_g->m_f();

pa_l->v_f(); //调用虚函数必须借助虚表指针间接寻址,因此需要对象,这里因为没对象而崩掉
pa_g->v_f();

return 0;
}

假如按照你说的只对堆上的气作用,那我现在在栈上或者全局区测试,为了验证调用虚函数必须经过虚表指针,所以,我这里特意用指针,且指针没指向对象,在这种情况下,调用一般成员函数是可以寻址到的,因为掉用普通成员函数的寻址方式不需要对象,而仅仅依赖调用者得类型,但是,调用虚函数时就会蹦,就是因为掉用虚函数需要访问对象内存中的虚表指针来跳转到虚函数的位置
pathuang68 2011-08-26
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 healer_kx 的回复:]

我真的看不懂。。。
[/Quote]

那还不错,至少可以解脱。

俺似懂非懂滴,这是最麻烦的了...
turing-complete 2011-08-26
  • 打赏
  • 举报
回复
这个我严重不能同意,编译器的实现者在给自己找麻烦,完事儿再挨骂?
贪食蛇男 2011-08-26
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 pengzhixi 的回复:]

静态绑定 动态绑定的区别。
[/Quote]
哦,原来如此。学习了!
pengzhixi 2011-08-26
  • 打赏
  • 举报
回复
你这属于研究过头了,然后忽然忘记了多态的基本条件。
飞天御剑流 2011-08-26
  • 打赏
  • 举报
回复
这头驴又发咆了……
pengzhixi 2011-08-26
  • 打赏
  • 举报
回复
静态绑定 动态绑定的区别。
Meteor_Code 2011-08-26
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 meteor_code 的回复:]
a_h.fun
用点操作符,是永远通过虚表调用成员函数的
[/Quote]
少个字
用点操作符,是永远"不"通过虚表调用成员函数的
贪食蛇男 2011-08-26
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 pengzhixi 的回复:]

你前面用的是对象直接调用,后面用的是引用调用能一样么?
[/Quote]
求解对象调用和引用调用有什么区别
加载更多回复(5)

64,642

社区成员

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

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