关于虚函数调用关系的问题

acdbxzyw 2012-08-30 05:20:39
今天笔试有关于虚函数的题,扩展了一下,主要分为三部分:
1、父类对象调用虚函数,父类指针或引用调用虚函数
2、父类函数非虚,子类同名函数为虚
3、作用域符号下中的函数寻址

得到如下测试代码及结果,烦请指点测试结果分析是否正确。。。
主要是1, 7, 9, 11的结果分析,以及其他。。。

#include <iostream>
#include <string.h>
using namespace std;

class Base
{
public:
virtual void fun(){ cout<<"base fun"<<endl;}

void is_virtual(){cout<<"base not virtual"<<endl;}
};

class Derived: public Base
{
public:
virtual void fun(){ cout<<"derived fun"<<endl;}

virtual void is_virtual(){cout<<"derived virtual"<<endl;}
};

void Print1(Base b)
{
b.fun();
}

void Print2(Base *p)
{
p->fun();
}

void Print3(Base &b)
{
b.fun();
}

int main()
{
Derived d;
Print1(d); //base fun //1 传值,创建了新Base对象,虚表指针由编译器初始化
Print2(&d); //derived fun //2 原对象,虚表指针指向Derived
Print3(d); //derived fun //3 原对象
cout<<"--------"<<endl;

Base *b = new Base();
memcpy(b, &d, sizeof(Base));
Print1(*b); //base fun //4 传值,新Base对象
Print2(b); //derived fun //5 原对象Base部分,虚表指针指向Derived
Print3(*b); //derived fun //6 原对象Base部分
cout<<"--------"<<endl;

d.Base::fun(); //base fun //7 Base命名空间寻址,编译器完成
cout<<"--------"<<endl;

Base *pb = NULL, *pb2=new Derived;
pb2->is_virtual(); //base not virtual //9 根据指针类型查找Base类命名空间该函数,为非虚函数,静态绑定
pb->is_virtual(); //base not virtual //8 非虚函数,静态绑定
b->is_virtual(); //base not virtual //10 非虚函数,静态绑定
cout<<"--------"<<endl;

d.is_virtual(); //derived virtual //11 在Derived对象内存中进行函数寻址
Derived *pd = new Derived;
pd->is_virtual(); //derived virtual //12 动态绑定,在Derived对象内存中进行函数寻址
d.Base::is_virtual(); //base not virtual //13 Base命名空间寻址,编译器完成

delete b;
delete pb2;
delete pd;
return 0;
}
...全文
273 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
acdbxzyw 2012-08-30
  • 打赏
  • 举报
回复
感谢您如此用心回复,受益良多!!!
[Quote=引用 7 楼 的回复:]

挺好的题目!!

C/C++ code

int main()
{
Derived d;
//Base temp((Base&)d); //对象被切割了
//within Print1, temp.Base::fun() 因为temp的动态类型是Base
Print1(d);

// Derived* p = &d; Bas……
[/Quote]
healer_kx 2012-08-30
  • 打赏
  • 举报
回复
5,6还好,主流的编译器,基本都能保证OK。

你试一试虚继承的,Derived class带着一个virtual Base2.

你再覆盖,当然了,不会覆盖到虚表指针那里,但是也许成员被覆盖错误了。
mujiok2003 2012-08-30
  • 打赏
  • 举报
回复
挺好的题目!!


int main()
{
Derived d;
//Base temp((Base&)d); //对象被切割了
//within Print1, temp.Base::fun() 因为temp的动态类型是Base
Print1(d);

// Derived* p = &d; Base* temp = p;
// temp->Derived::fun,因为temp的动态类型是Derived*,虽然静态类型(申明类型)为Base*
//指针传值, 动态绑定
Print2(&d);
// Base& temp = d;
// temp.Derived::fun,因为temp的动态类型是Derived,虽然静态类型(申明类型)为Base
Print3(d); //Base& temp;
cout<<"--------"<<endl;

Base *b = new Base();
//因为Base和Derived有相同的内存布局, 所以完成memcpy后,b的动态类型已经是Derived*, 因为它vptr已经指向了Derived的vtable
//这种用法很危险!!
memcpy(b, &d, sizeof(Base));
//到此完全上面的3种情况了,不解释了
Print1(*b); //base fun //4 传值,新Base对象
Print2(b); //derived fun //5 原对象Base部分,虚表指针指向Derived
Print3(*b); //derived fun //6 原对象Base部分
cout<<"--------"<<endl;
//显示调用,没有用动态绑定, 在编译时确定了
d.Base::fun(); //base fun //7 Base命名空间寻址,编译器完成
cout<<"--------"<<endl;

//pb,pb2的静态类型为Base*, pb2的动态类型为Derived*, pb没有动态类型,因为它并没有指向一个实例
Base *pb = NULL, *pb2=new Derived;
//is_virtual的调用者静态类型如果是Base, Base*, Base&,则没有静态绑定的
//is_virtual的调用者静态类型如果是Derived, Derived*, Derived&,则动态绑定, 编译插入了查找vtable的指令
pb2->is_virtual(); //base not virtual //9 根据指针类型查找Base类命名空间该函数,为非虚函数,静态绑定
pb->is_virtual(); //base not virtual //8 非虚函数,静态绑定
//b的静态类型为Base*
b->is_virtual(); //base not virtual //10 非虚函数,静态绑定
cout<<"--------"<<endl;

//d的静态类型为Derived
d.is_virtual(); //derived virtual //11 在Derived对象内存中进行函数寻址
Derived *pd = new Derived;
//pd的静态类型是Drived*
pd->is_virtual(); //derived virtual //12 动态绑定,在Derived对象内存中进行函数寻址
//所有显示调用都是静态绑定的!
d.Base::is_virtual(); //base not virtual //13 Base命名空间寻址,编译器完成
acdbxzyw 2012-08-30
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

1、切割---编译器调整虚表指针
5 6 可能会崩
8 9 10 没有研究过类似问题。。。
[/Quote]
5 6 可能会崩
是说内存布局是跟编译器有关是吗?
acdbxzyw 2012-08-30
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

引用 2 楼 的回复:

memcpy(b, &d, sizeof(Base));
这句代码是错误的代码


++,楼主可明白这条语句的真正含义?

楼主如果对此类问题感兴趣,建议最好去看看《Inside C++ Object Model》
[/Quote]
《Inside》看过了,又差不多忘了。。。你们都是过目不忘的大牛!!!
求指点。。。
通求指点其他语句。。。
acdbxzyw 2012-08-30
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

memcpy(b, &d, sizeof(Base));
这句代码是错误的代码
[/Quote]

求指点。。。在这种环境下都会有问题吗?按内存布局来说,子类对象的前部分应该是父类对象的成员吧。。。
pathuang68 2012-08-30
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

memcpy(b, &d, sizeof(Base));
这句代码是错误的代码
[/Quote]

++,楼主可明白这条语句的真正含义?

楼主如果对此类问题感兴趣,建议最好去看看《Inside C++ Object Model》
pengzhixi 2012-08-30
  • 打赏
  • 举报
回复
memcpy(b, &d, sizeof(Base));
这句代码是错误的代码
nightkids_008 2012-08-30
  • 打赏
  • 举报
回复
1、切割---编译器调整虚表指针
5 6 可能会崩
8 9 10 没有研究过类似问题。。。

65,187

社区成员

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

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