【转】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装着对应类的虚函数地址,这样虚函数就可以完成它的任务了。

原文地址:https://www.cnblogs.com/qxxnxxFight/p/11131622.html

时间: 2024-10-12 13:42:22

【转】c++中使用memset初始化类对象的相关文章

springmvc中配置servlet初始化类

<bean  id="InitStart" lazy-init="false" init-method="InitSystem" class="my.spring.uitl.InitStart"></bean> 配置在springmvc的配置文件中 只要项目启动,就会默认执行这个类的这个方法 相比静态类代码块的好处, 有点在tomcat启动时就会调用如果有错立即报错,静态代码块,调用时才会报错 作用 可

MFC中CAsyncSocket及其派生类对象跨线程使用方法

存在的现象 在MFC中用多线程方法开发WinSocket通讯程序时,如果你的的是API方式,自然没有以下说的问题.但如果当你使用CAsyncSocket及其派生类(CSocket或是你自己的写的)来开发的话,会发现在不同线程中使用CAsyncSocket及其派生类对象时,会出现程序崩溃.这里所说的跨线程,是指该对象在一个线程中调用Create/Close/Attach/Detach函数,然后在另外一个线程中调用其他成员函数如Receive/ReceiveFrom/Send/SendTo等.下面是

memset初始化类 在调用虚函数时的出错分析

偶尔 在群里看见 一段代码的问题,自己敲了下 试了试 总结一下:代码: #include <cstring> #include <iostream> using namespace std; class Parent { public: Parent(){} virtual void output(); }; void Parent::output() { cout << " Parent " << endl; } class son:p

JAVA中 Map转换实体类对象简单实现 JSON

原文链接:https://blog.csdn.net/qq_23140197/article/details/86503875   (侵删) 开发的过程中往往依赖的表过多直接按Map来传递数值,某些场景需要把Map转换为实体类,这里贴一个最简洁的方法,依赖阿里的FastJSon. maven引入 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId>

C#中使用反射原理创建类对象

用例: 现在有一个命名空间为Device的Device.dll文件,它含两个类Device1和Device2:现通过反射原理创建Device1和Device2类,具体语句如下: //1.首先需要添加引用    using System.Reflection; //2.创建Device1 Assembly AsmDevice = Assembly.Load("Device");//加载命名空间 Type Device1Type= AsmDevice.GetType("Devic

实例化类对象中alloc和inti的区别

在OC中,实例化一个类对象需要通过调用alloc和init两个系统既定方法进行初始化,比如: Fraction *frac=[[Fraction alloc]init]; 两者的区别如下: 1.alloc方法保证对象所对应的类里定义的所有实例变量都变成初始状态,但并没有使该对象本身进行初始化: 2.init方法用于初始化类要实例化的对象,它可以返回一个值,即被初始化的对象. ps:当然实例化一个对象还可以采用一种简便的方式,比如: Fractiion *frac=[Fraction new];

类对象初始化

1 using System; 2 /// <summary> 3 /// 命名空间 4 /// </summary> 5 namespace myspace 6 { 7 /// <summary> 8 /// 命名空间中的类 9 /// </summary> 10 class myclass 11 { 12 13 static void Main(string[] a) 14 { 15 //string[] mybook = new string[] {

22.python中的面向对象和类的基本语法

当我发现要写python的面向对象的时候,我是踌躇满面,坐立不安呀.我一直在想:这个坑应该怎么爬?因为python中关于面向对象的内容很多,如果要讲透,最好是用面向对象的思想重新学一遍前面的内容.这个坑是如此之大,犹豫再三,还是只捡一下重要的内容来讲吧,不足的内容只能靠大家自己去补充了. 惯例声明一下,我使用的版本是 python2.7,版本之间可能存在差异. 好,在开讲之前,我们先思考一个问题,看代码: 为什么我只创建是为 a 赋值,就可以使用一些我没写过的方法? 可能会有小伙伴说:因为 a

24-oc类工厂方法和类对象基本概念

类工厂方法 用于快速创建对象的类方法, 我们称之为类工厂方法 类工厂方法应用场景 类工厂方法中主要用于给对象分配存储空间和初始化这块存储空间 类工厂方法使用规范 规范: 一定是类方法 + 方法名称以类的名称开头, 首字母小写 一定有返回值, 返回值是id/instancetype 在类工厂方法实现中,调用本类的构造方法,创建实例对象,并返回实例对象 自定义类工厂方法是苹果的一个规范, 一般情况下, 我们会给一个类提供自定义构造方法和自定义类工厂方法用于创建一个对象 类工厂方法在继承中的注意点 以