在类的构造函数中使用memset(this,0,sizeof(*this)), 会产生什么效果?代码如下,不解...

wang603603 2013-11-05 10:05:08


class ClassA
{
public:
ClassA()
{
cout<<"A: "<<this<<endl;
Clear();
}

void Clear()
{
memset(this,0,sizeof(*this));
}

~ClassA()
{
}
virtual void func()
{
cout<<"func.A "<<endl;
}
};

class ClassB:public ClassA
{
public:
ClassB()
{
cout<<"B: "<<this<<endl;
}
void func()
{
cout<<"func.B "<<endl;
}

};

int main()
{

ClassA a;
ClassB b;

ClassA *pa = &a;
ClassA *pab = &b;
ClassB* pb = &b;

a.func(); //1 func.A
b.func(); //2 func.B
pa->func(); //3 异常
pab->func(); //4 func.B
pb->func(); //5 func.B
return 1;
}


按照正常的理解, 第一个也应该出现异常,此时vptr的值为0x000000! 怎么会出现这样的结果, 请指教!

(我认为: 在CLassB类的对象b中,虚表指针其实 已经不属于 基类部分了, 所以在构造函数中去 调用memset(..) 并不影响 vptr的值,根据调试来看 也确实如此!)。

...全文
724 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
lm_whales 2013-11-07
  • 打赏
  • 举报
回复
引用 12 楼 seanxq 的回复:
首先,通过对象调用,不允许多态。 ClassB *b = new ClassB; ClassA *a = b; *a.func(); // 编译器会直接报错。 其次,仔细观察ClassB对象构造的过程。 - 父类先构造,内存结构如下: vtpr, Class A data // 注意这里的vtpr是指向Class A的虚表 - 然后你把指向上述地址的内存给清零了 - 然后是子类构造, 会有如下几步: > 更新vtpr,指向Class B的虚表 // vtpr有新值啦 > 初始化Class B的数据 > 最后内存结构如: vtpr of Class B, Class A data, Class B data 这样就不难理解楼主的问题了 1. a.func(); //1 func.A b.func(); //2 func.B 不涉及多态,没访问虚表 2. pa->func(); //3 异常 因为vtpr被清零,访问虚表出错; 2. pab->func(); //4 func.B pb->func(); //5 func.B 因为是ClassB的object, 在构造中,最终的vtpr是指向Class B的虚表, 其vtpr是有效的值
++
boyka913 2013-11-07
  • 打赏
  • 举报
回复
请遵守一个规则“禁止在类中使用memset对类进行初始化”,否则你会哭的。
seanxq 2013-11-06
  • 打赏
  • 举报
回复
首先,通过对象调用,不允许多态。 ClassB *b = new ClassB; ClassA *a = b; *a.func(); // 编译器会直接报错。 其次,仔细观察ClassB对象构造的过程。 - 父类先构造,内存结构如下: vtpr, Class A data // 注意这里的vtpr是指向Class A的虚表 - 然后你把指向上述地址的内存给清零了 - 然后是子类构造, 会有如下几步: > 更新vtpr,指向Class B的虚表 // vtpr有新值啦 > 初始化Class B的数据 > 最后内存结构如: vtpr of Class B, Class A data, Class B data 这样就不难理解楼主的问题了 1. a.func(); //1 func.A b.func(); //2 func.B 不涉及多态,没访问虚表 2. pa->func(); //3 异常 因为vtpr被清零,访问虚表出错; 2. pab->func(); //4 func.B pb->func(); //5 func.B 因为是ClassB的object, 在构造中,最终的vtpr是指向Class B的虚表, 其vtpr是有效的值
Saleayas 2013-11-06
  • 打赏
  • 举报
回复
虚函数只有在引用的时候,才通过虚表调用的。 否则是直接编译到指定的函数。 引用在 C++ 里面有两种: reference 和 pointer。 static_cast<ClassA &>(a).func(); (&a)->func();
xiaohuh421 2013-11-06
  • 打赏
  • 举报
回复
ClassB() 012D5DB0 push ebp 012D5DB1 mov ebp,esp 012D5DB3 push ecx 012D5DB4 push esi 012D5DB5 mov dword ptr [ebp-4],0CCCCCCCCh 012D5DBC mov dword ptr [ebp-4],ecx 012D5DBF mov ecx,dword ptr [this] 012D5DC2 call ClassA::ClassA (12D5CD0h) //先调用了基类构造函数 012D5DC7 mov eax,dword ptr [this] 012D5DCA mov dword ptr [eax],offset ClassB::`vftable' (1392E5Ch) //再分配虚表. 反汇编一看, 就明了了. 因为对于类B, 是在调用了A类构造函数后, 才初始化的虚表, 所以你有A类中的memset对B类的虚表无作用.
SKATE11 2013-11-05
  • 打赏
  • 举报
回复
类的初始化会自动初始化指向虚表的指针 这个指针一般放在类的第一个位置处 楼主memset后会导致对像无法寻址到虚表 所以虚函数调用异常 一般成员函数应该没问题
lunat 2013-11-05
  • 打赏
  • 举报
回复
1.通过对象调用时,编译器直接生成调用的地址; 2.通过指针或者引用调用时,在运行期通过虚表指针查询调用的地址; 3.子类构造时,重建了虚表指针;
不良制品 2013-11-05
  • 打赏
  • 举报
回复
经过测试发现是virtual声明的问题,应该是memset(this,0,sizeof(*this));将虚函数指针给制0了,结果通过A类指针去调用虚函数时,会去调用虚函数指针,此时无法找到正确的函数地址,结果出现异常。而用变量去调用时没有通过虚函数指针来调用,而是直接调用的A类中的fun函数的地址。因为如果将virtual去掉就可以正常通过。
fishion 2013-11-05
  • 打赏
  • 举报
回复
如果把 ClassA a; ClassB b; 定义为 ClassA *a = new ClassA; ClassB *b = new ClassB; 这时调用a->func()就出错了 可能是以对象调用方法时不通过虚表来查找方法吧
lm_whales 2013-11-05
  • 打赏
  • 举报
回复
单一直接继承,子类,和子类内部的父类子对象,虚表指针的地址没变,但是虚表变了。 这样,内部的父类子对象的虚表指针,就被覆盖了。不在是0了。
lm_whales 2013-11-05
  • 打赏
  • 举报
回复
子类对象重载了虚函数,所以子类构造时候,重建了虚函数表。 另外 具体实现,看编译器 单一直接继承,VC 的虚表指针,指向的虚表有两项, 子类虚函数在第一项,父类虚函数在第二项 同时有父类虚函数表,和子类虚函数表两个表,只有一个虚表指针。 另外对象调用虚函数,可能是静态绑定的。 多态是指针,引用干的事。
版主大哥 2013-11-05
  • 打赏
  • 举报
回复
应该是直接寻址很间接寻址导致的问题
turing-complete 2013-11-05
  • 打赏
  • 举报
回复
初步鉴定,可能是函数静态绑定和动态绑定,造成的差异。
赵4老师 2013-11-05
  • 打赏
  • 举报
回复
《深度探索C++对象模型》 《C++反汇编与逆向分析技术揭秘》

65,210

社区成员

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

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