欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    类和动态内存分配.ppt

    • 资源ID:6329506       资源大小:242.99KB        全文页数:61页
    • 资源格式: PPT        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    类和动态内存分配.ppt

    第7章 类和动态内存分配,提要,本章介绍对类使用动态分配技术,以及由此引起的问题的处理。动态内存的使用将影响构造函数,析构函数的设计和操作符的重载,7.1 动态内存和类,一个使用动态内存的例子class StringBadprivate:char*str;/pointer to string int len;/length of string static int num_strings;/number of objectspublic:StringBad(const char*s);/constructor StringBad();/default constructor StringBad();/destructor/friend functionfriend std:ostream,以下是其实现(stringbad.cpp)静态类成员的初始化int StringBad:num_strings=0;/注意:静态类成员位于静态存储区,并不是类对象的组成部分;在类声明中声明,不可初始化(静态const整型或枚举除外除外);在类方法实现文件中初始化。使用类型名和定义域限制操作符,不用关键字static。,然后是构造函数StringBad:StringBad(const char*s)len=std:strlen(s);/set size str=new charlen+1;/allot storage std:strcpy(str,s);/initialize pointer num_strings+;/set object count cout num_strings:str object createdn;/For Your Information注意:字符串并没有保存在对象中,而是在单独的堆内存中。对象中存储字符串的地址。,析构函数StringBad:StringBad()/necessary destructor cout str object deleted,;/FYI-num_strings;/required cout num_strings leftn;/FYI delete str;/required此处析构函数是必须的。在构造函数中用new分配内存,必须在析构函数中用delete释放内存,文件vegnews.cpp是使用上述类的主程序。其中定义了两个函数:一个传引用作参数,一个传值作参数void callme1(StringBad,1:Celery Stalks at Midnight object created2:Lettuce Prey object created3:Spinach Leaves Bowl for Dollars object createdheadline1:Celery Stalks at Midnightheadline2:Lettuce Preysports:Spinach Leaves Bowl for DollarsString passed by reference:Celery Stalks at Midnightheadline1:Celery Stalks at MidnightString passed by value:Lettuce PreyLettuce Prey object deleted,2 leftheadline2:葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺,Initialize one object to another:sailor:Spinach Leaves Bowl for DollarsAssign one object to another:3:C+default object createdknot:Celery Stalks at MidnightEnd of main()Celery Stalks at Midnight object deleted,2 leftSpinach Leaves Bowl for Dollars object deleted,1 left葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺?object deleted,0 left未处理的异常:System.NullReferenceException:未将对象引用设置到对象的实例。at delete(Void*)at StringBad._dtor(StringBad*)in d:temptest2strngbad.cpp:line 37 at main()in d:temptest2vegnews.cpp:line 39,C+object deleted,-1 left葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺F object deleted,-2 left未处理的异常:System.NullReferenceException:未将对象引用设置到对象的实例。at delete(Void*)at StringBad._dtor(StringBad*)in d:temptest2strngbad.cpp:line 37 at _CxxCallUnwindDtor(IntPtr,Void*)at main()in d:temptest2vegnews.cpp:line 39,跟踪程序的执行过程,当函数callme2调用时发生了析构函数的调用。析构函数的delete语句释放了实际参数headline对象的成员headline.str指向的内存,并使静态成员的计数减一:cout str object deleted,;-num_strings;/required cout num_strings leftn;/FYI delete str;注意:当以对象为实参传递给函数时,函数中要拷贝对象的副本,即创建一个临时对象;该函数结束时临时对象消失,析构函数被调用。,分析程序:拷贝构造函数,程序中没有给出拷贝构造函数,但却使用了拷贝构造函数:当用一个对象初始化一个新建对象时StringBad sailor=sports;StringBad sailor(sports);函数按值传递对象或返回对象时callme2(headline2);,此时使用了默认的拷贝构造函数,即按值依次复制对象的非静态变量成员。该拷贝构造函数的原型如下:Stringbad(const Stringbad 相当于sailor.str=sports.str即两个指针值相同,它们指向了同一块内存另外,默认拷贝构造函数不会对静态成员有改变,所以计数不增加。,注意1:如果类中有这样的静态成员,当创建对象时其值发生改变,必须提供显式的拷贝构造函数注意2:如果类中有用new初始化的指针成员,应该提供显式的拷贝构造函数,以实现深拷贝StringBad:StringBad(const StringBad/copy string to new location,分析程序:赋值操作符,程序中允许对类对象赋值,是因为c+自动为类重载了赋值操作符。如StringBad knot;knot=headline1;使用了下面的自动重载的操作符Stringbad 默认赋值操作符的实现方式与默认拷贝相似,也是对成员进行逐个复制,但不影响静态数据成员,由于 knot=headline1;赋值操作符作了如下的工作:knot.str=headline1.str;同样是两个指针指向了同一块内存。对象knot的析构函数调用在先,释放了指针指向的内存;当对象headline1的析构函数被调用时试图释放已经释放的内存导致错误。,解决该问题的方法是提供赋值操作符的重载,实现深拷贝。重载赋值操作符应具有如下功能:由于被赋值的对象在创建时已经分配了内存,所以函数使用前应该先释放它;函数要避免自身赋值,否则赋值前的释放内存操作会破坏对象的内容;函数返回一个指向对象的引用,这样可以实现连续赋值操作。,重载的操作符如下StringBad,改进后的字符串类,增加拷贝构造函数和赋值操作符添加必要的功能1.修订默认构造函数:构建一个空字符串String:String()/default constructor len=0;str=new char1;/为何不是new char?str0=0;/default string num_strings+;,2.比较成员函数:比较字符串的前后顺序bool operator(const String,比较操作符都被设置为友元,有利于C字符串与对象的比较,例如,name是一个对象 if(“Smith”=name)可以转换为 if(operator=(“Smith”,name)再由一个构造函数将“Smith”转换为类类型从而进行函数的调用3.重载下标运算符 运算符的一个操作数位于括号前,一个操作数位于两个括号之间。char,/这个方法可以为对象的特定元素赋值String name(“john smith”);name0=J;name5=S;但是非const成员不能被const对象使用,所以还要定义一个const 函数const char,4.静态类成员函数/static function static int HowMany();/static methodint String:HowMany()return num_strings;静态类成员函数的作用:不能通过对象调用它,它也只能访问静态数据成员声明为公有,则可以由作用域操作符调用它:Int count=String:HowMany();,5.再增加一个赋值操作符String 通过这个方法可以用字符串对对象赋值,6.重载输出输入操作符ostream,小结:构造函数中使用new,构造函数中使用new初始化指针成员,则析构函数重要使用delete;new和delete须兼容;如果有多个构造函数,必须以同样方式使用new,也可以将指针成员初始化为0;应定义拷贝构造函数,实现深拷贝,其中还要注意更新受影响的静态成员;应定义赋值操作符,实现深拷贝。,有关函数返回对象的总结,返回指向const对象的引用对象引用作函数参数是为提高效率,不用复制对象,const表示不可改动实参如果函数要返回传递给它的对象,也可以通过传引用提高效率。const Vector 此例中可以返回对象,但要调用拷贝构造函数,降低效率。const 与参数对应。,返回指向非const对象的引用常用于重载赋值操作符和与流对象一起用的操作符。ostream&operator(ostream&os,const String&st)必须返回ostream&,以便实现连续输出。不能返回对象,因ostream没有公有的拷贝构造函数。也不能是const,因为流对象的值在改变。String&String:operator=(const String&st)可以返回对象或引用,都可起到连续赋值作用,但返回引用效率高。,返回对象如果函数中要返回的是个局部对象,则不能返回引用,因为返回时该对象已消失,引用指向的对象将不存在。例如重载的算术运算符Vector Vector:operator+(const Vector,返回const对象前面的operator+允许以下操作Vector step1(50,40);Vector step2(38,77);Vector total;total=step1+step2;step1+step2=total;if(step1+step2=step1)cout“step2=0.”解决方法:将operator+的类型声明为const对象,指向对象的指针,在C+中,经常使用指向对象的指针,下面的例子演示了这种用法。(sayings2.cpp)可以使用普通的指针方法来使用对象指针,例如 String*shortest=,之后便可以利用指针间接访问if(sayingsi.length()length()或者对指针解除引用if(sayingsi*first),使用new初始化对象,如果className是类,value的类型为typeName,则语句className*pclass=new className(value);将调用构造函数className(typeName);例如String*pst=new String(“Hello.”);将调用String(const char*s);而String*pst=new String;将调用默认构造函数String();,一个特殊情况String*favorite=new String(sayingschoice);所给的参数是一个本类对象的名字,则调用的是拷贝构造函数String(const String/copy constructor,刚才的例子中在两个层次上使用了new和delete操作符:一是为创建每一个对象包含的字符串分配存储空间,这是在构造函数中进行的,需要在析构函数中释放该空间String:String(const char*s)/construct String from/C string len=std:strlen(s);/set size str=new charlen+1;/allot storage std:strcpy(str,s);/initialize pointer num_strings+;/set object count,String:String()-num_strings;delete str;第二个层次是为类对象分配空间,保存的是类对象的成员str指针值和字符串的长度值lenString*favorite=new String(sayingschoice);cout My favorite saying:n*favorite endl;delete favorite;,保存对象的空间不会由析构函数释放,需要用delete释放它:只释放存放str和len的空间,而不会释放保存字符串的空间析构函数的调用有以下几种情况:如果对象是自动变量,则执行完定义该对象的程序块时调用如果对象是静态的(静态,外部,静态外部的),则在程序结束时调用如果对象是由new创建的,则当显式地使用delete时调用析构函数,class Act;Act nice;/外部对象int main()Act*pt=new Act;/动态对象Act myact;/自动对象/调用myact的析构函数delete pt;/调用(*pt)的析构函数/调用nice 的析构函数,使用new为对象分配空间的机制比较复杂:String*mystring=new String(“hello baby.”);1、为对象分配内存2、调用类构造函数为“hello baby.”分配空间,并将字符串复制到分配的空间中,str:len:(对象地址:2400),Hello baby.0(字符串地址:2000),将字符串的地址值赋给str,将字符串的长度值赋给len,并且更新mun_strings3、创建指针变量mystring,将新对象的地址赋给变量mystring,str:2000len:11(对象地址:2400),指针值:2400(变量地址:2800),布局new操作符,通常情况,new 负责在堆中找一个足以满足要求的内存块;new还有一种变体称为布局new操作符,允许指定要使用的位置。通过布局new可以设置内存管理规程,或处理通过特定地址访问的硬件。使用布局new需要头文件,且要指定new的参数。,#include Struct chaff char dross20;int slag;char buffer150;char buffer2500;int main()chaff*p1,*p2;int*p3,*p4;p1=new chaff;p3=new int 20;p2=new(buffer1)chaff;p4=new(buffer2)int20;,看一个例子。从中可以知道pd2通过布局new放在了buffer中,而pd1被放在很远的堆中第二个常规new查找一个新的内存块,而第二个布局new分配的位置与第一次一样。说明布局new使用传递给它的地址,它不跟踪内存单元已被使用。操作符delete 只能用于释放常规操作符new分配的堆内存,本例中的buffer是静态内存,不能使用delete来释放。,布局new用于对象,看一个使用布局new创建对象的例子(placenew1.cpp)程序存在两个问题:pc1和pc3均由布局new创建,后者创建时会覆盖前者的内存。如果对象中的成员是由new来动态分配的,会引发问题(布局new使用指定位置,而创建成员的new要查找空闲位置)。将delete用于pc2和pc4时会自动调用它们指向的对象的析构函数;delete用于buffer时释放常规new创建的整个内存块,不会调用在其中创建的对象(由布局new创建)的析构函数。,解决第一个问题的方法是程序员来控制为布局new提供不同的地址,例如pc1=new(buffer)JustTesting;pc3=new(buffer+sizeof(JustTesting)JustTesting(Better Idea,6);解决第二个问题的方法是显式地调用由布局new创建对象的析构函数pc3-JustTesting();/destroy object pointed/to by pc3pc1-JustTesting();/destroy object pointed/to by pc1需要注意,以创建对象相反的顺序删除之,并且删除完对象之后再释放所在的缓冲区。,7.2 队列模拟,问题:一家银行想在一家超市中建立ATM机,超市担心排队会影响其经营。编程模拟ATM对超市造成的影响。使用队列描述排队顾客:队列中的项为顾客。假设,1/3的顾客1分钟接受服务,1/3为2分钟,另外1/3为3分钟;顾客的到达时间随机,但每小时到达的顾客数恒定。,设计队列类,应有如下特征:存储有序项序列容纳的项目数有一定限制能够创建空队列能够判断队列为空或为满可以从队尾添加项可以从队首删除项能够确定队列中的项目数,队列类的接口:class Queueenum Q_SIZE=10;public:Queue(int qs=Q_SIZE);/create queue with a qs limit Queue();bool isempty()const;bool isfull()const;int queuecount()const;bool enqueue(const Item,队列数据的表示使用链表表示。链表由节点构成,每个节点中保存相应信息以及指向下一个节点的指针,队尾的指针通常指向NULL。struct Node Item item;struct Node*next;此外还要有链表的起始位置,末尾位置,可存储的最大项数以及当前存储的项数。可以如下设计队列类的数据成员:,class Queueprivate:/class scope definitions/Node is a nested structure definition local to this class struct Node Item item;struct Node*next;enum Q_SIZE=10;/private class members Node*front;/pointer to front of Queue Node*rear;/pointer to rear of Queue int items;/current number of items in Queue const int qsize;/maximum number of items in Queue,队列最初是空的,所以Queue:Queue(int qs):qsize(qs)front=rear=NULL;items=0;注意:非静态常量数据成员和引用数据成员不能赋值,但又不能在类定义中初始化。只能使用成员初始化列表方式初始化,归纳:static,const成员的初始化问题,static const成员是类中的常数,在类定义中初始化即可:class Test static const int size=10;static 成员在类中声明,其初始化要放在类定以外,通常是在实现文件中,例如 class Test static int size;,/实现文件int Test:size=10;/成员定义const成员,在类定义中声明,在构造函数的成员初始化列表中初始化,如前面的例子。,判断队列为空、为满和确定队列中项目个数的成员函数如下:bool Queue:isempty()const return items=0;bool Queue:isfull()const return items=qsize;int Queue:queuecount()const return items;,bool Queue:enqueue(const Item,bool Queue:dequeue(Item,队列中的节点是用new添加的,因此,在析构函数中要用delete释放节点占用的空间:Queue:Queue()Node*temp;while(front!=NULL)/while queue is not yet empty temp=front;/save address of front item front=front-next;/reset pointer to next item delete temp;/delete former front,客户类class Customerprivate:long arrive;/arrival time for customer int processtime;/processing time for customerpublic:Customer()arrive=processtime=0;void set(long when);long when()const return arrive;int ptime()const return processtime;void Customer:set(long when)processtime=std:rand()%3+1;arrive=when;,模拟输入:队列最大长度,模拟时间,每小时客户数程序使用循环,每次循环代表一分钟,其间完成如下步骤:判断是否有新客户,决定将其加入队列与否如果没有客户交易,从队列中取出第一个客户,确定其已等待时间,并将wait_time设置为新客户所需的处理时间如果客户正在处理中,将wait_time减1统计各种数据,如何确定是否有新客户到来bool newcustomer(double x)return(std:rand()*x/RAND_MAX)是rand()可能返回的最大值。rand()*x/RAND_MAX 的值位于0-x之间,每过x分钟,平均有一次该值小于1。,

    注意事项

    本文(类和动态内存分配.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开