【转】c++中使用memset初始化类对象

 https://blog.csdn.net/u010261063/article/details/70064090

 1 #include <iostream>
 2 #include <memory.h>
 3 using namespace std;
 4 
 5 class parent{
 6 public:
 7     virtual void output();
 8     virtual void output2();
 9 };
10 
11 void parent::output(){
12     cout << "parent output" << endl;
13 }
14 
15 void parent::output2(){
16     cout << "parent output2" << endl;
17 }
18 
19 class son : public parent{
20 public:
21     void output();
22 };
23 
24 void son::output(){
25     cout << "son" << endl;
26 }
27 
28 int main(){
29     son s;
30     // memset(&s, 0, sizeof(s));  // 会段错误
31     cout << "sizeof(s)=" << sizeof(s) << endl;  // 输出为8 没虚函数时1
32     parent& p = s;
33     p.output();
34     return 0;
35 }

输出程序运行结果:程序不输出结果,运行出错!!分析一下原因:

在使用memset初始化对象Obj之前,通过Obj调用output函数时程序运行正常,但是一旦利用Memset函数初始化该对象,再对该obj调用Show和Print函数,则程序立马崩溃。

究其原因是因为初始化obj的时候,将obj包含的指向虚函数表VTBL的指针也清除了。包含虚函数的类对象都有一个指向虚函数表的指针,此指针被用于解决运行时和动态类型强制转换时虚函数的调用问题。

该指针是被隐藏的,对程序员来说,这个指针也是不可存取的。当进行memset操作时,这个指针(即指向虚函数表的地址)的值也要被初始化,这样一来,只要一调用虚函数,程序便会崩溃。
这种现象在很多由C转向C++的程序员来说,很容易犯这个错误,而且这个错误很难查。

为了避免这种情况,记住对于有虚拟函数的类对象,决不能使用memset来进行初始化操作。而是要用缺省的构造函数或其它的init例程来初始化成员变量。

 

当类中有虚函数的时候,编译器会为类插入一个我们看不见的数据并建立一个表。这个表就是虚函数表(vtbl),那个我们看不见的数据就是指向虚函数表的指针——虚表指针(vptr)。

虚函数表就是为了保存类中的虚函数的地址。我们可以把虚函数表理解成一个数组,数组中的每个元素存放的就是类中虚函数的地址。

当调用虚函数的时候,程序不是像普通函数那样直接跳到函数的代码处,而是先取出vptr即得到虚函数表的地址,根据这个来到虚函数表里,从这个表里取出该函数的地址,最后调用该函数。

所以只要不同类的vptr不同,他对应的vtbl就不同,不同的vtbl装着对应类的虚函数地址,这样虚函数就可以完成它的任务了

posted on 2019-07-04 12:41  钱小小  阅读(674)  评论(0编辑  收藏  举报

导航