类和动态内存分配

上传人:san****019 文档编号:70182099 上传时间:2019-01-16 格式:PPT 页数:61 大小:206.01KB
返回 下载 相关 举报
类和动态内存分配_第1页
第1页 / 共61页
类和动态内存分配_第2页
第2页 / 共61页
类和动态内存分配_第3页
第3页 / 共61页
类和动态内存分配_第4页
第4页 / 共61页
类和动态内存分配_第5页
第5页 / 共61页
点击查看更多>>
资源描述

《类和动态内存分配》由会员分享,可在线阅读,更多相关《类和动态内存分配(61页珍藏版)》请在金锄头文库上搜索。

1、第7章 类和动态内存分配,提要,本章介绍对类使用动态分配技术,以及由此引起的问题的处理。 动态内存的使用将影响构造函数,析构函数的设计和操作符的重载,7.1 动态内存和类,一个使用动态内存的例子 class StringBad private: char * str; / pointer to string int len; / length of string static int num_strings; / number of objects public: StringBad(const char * s); / constructor StringBad(); / default c

2、onstructor StringBad(); / destructor / friend function friend std:ostream ,以下是其实现(stringbad.cpp) 静态类成员的初始化 int StringBad:num_strings = 0; /注意: 静态类成员位于静态存储区,并不是类对象的组成部分; 在类声明中声明,不可初始化(静态const整型或枚举除外除外); 在类方法实现文件中初始化。使用类型名和定义域限制操作符,不用关键字static。,然后是构造函数 StringBad:StringBad(const char * s) len = std:str

3、len(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 “ st

4、r “ 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 created 2: “Lettuce Prey“ objec

5、t created 3: “Spinach Leaves Bowl for Dollars“ object created headline1: Celery Stalks at Midnight headline2: Lettuce Prey sports: Spinach Leaves Bowl for Dollars String passed by reference: “Celery Stalks at Midnight“ headline1: Celery Stalks at Midnight String passed by value: “Lettuce Prey“ “Lett

6、uce Prey“ object deleted, 2 left headline2: 葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺,Initialize one object to another: sailor: Spinach Leaves Bowl for Dollars Assign one object to another: 3: “C+“ default object created knot: Celery Stalks at Midnight End of main() “Celery Stalks at Midnight“ object deleted, 2 left “Spinac

7、h 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,

8、 -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调用时发

9、生了析构函数的调用。析构函数的delete语句释放了实际参数headline对象的成员headline. str指向的内存,并使静态成员的计数减一: cout “ str “ object deleted, “; -num_strings; / required cout num_strings “ leftn“; / FYI delete str; 注意:当以对象为实参传递给函数时,函数中要拷贝对象的副本,即创建一个临时对象;该函数结束时临时对象消失,析构函数被调用。,分析程序:拷贝构造函数,程序中没有给出拷贝构造函数,但却使用了拷贝构造函数: 当用一个对象初始化一个新建对象时 String

10、Bad sailor = sports; StringBad sailor (sports); 函数按值传递对象或返回对象时 callme2(headline2);,此时使用了默认的拷贝构造函数,即按值依次复制对象的非静态变量成员。该拷贝构造函数的原型如下: Stringbad (const Stringbad 相当于sailor.str = sports.str 即两个指针值相同,它们指向了同一块内存 另外,默认拷贝构造函数不会对静态成员有改变,所以计数不增加。,注意1:如果类中有这样的静态成员,当创建对象时其值发生改变,必须提供显式的拷贝构造函数 注意2:如果类中有用new初始化的指针成员

11、,应该提供显式的拷贝构造函数,以实现深拷贝 StringBad:StringBad(const StringBad / copy string to new location ,分析程序:赋值操作符,程序中允许对类对象赋值,是因为c+自动为类重载了赋值操作符。如 StringBad knot; knot = headline1; 使用了下面的自动重载的操作符 Stringbad 默认赋值操作符的实现方式与默认拷贝相似,也是对成员进行逐个复制,但不影响静态数据成员,由于 knot = headline1; 赋值操作符作了如下的工作: knot.str = headline1.str; 同样是两个

12、指针指向了同一块内存。 对象knot的析构函数调用在先,释放了指针指向的内存;当对象headline1的析构函数被调用时试图释放已经释放的内存导致错误。,解决该问题的方法是提供赋值操作符的重载,实现深拷贝。 重载赋值操作符应具有如下功能: 由于被赋值的对象在创建时已经分配了内存,所以函数使用前应该先释放它; 函数要避免自身赋值,否则赋值前的释放内存操作会破坏对象的内容; 函数返回一个指向对象的引用,这样可以实现连续赋值操作。,重载的操作符如下 StringBad ,改进后的字符串类,增加拷贝构造函数和赋值操作符 添加必要的功能 1. 修订默认构造函数:构建一个空字符串 String:Strin

13、g() / 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. 重载下标运算符

14、 运算符的一个操作数位于括号前,一个操作数位于两个括号之间。 char ,/这个方法可以为对象的特定元素赋值 String name (“john smith”); name0 = J; name5 = S; 但是非const成员不能被const对象使用,所以还要定义一个const 函数 const char ,4. 静态类成员函数 / static function static int HowMany(); / static method int String:HowMany() return num_strings; 静态类成员函数的作用:不能通过对象调用它,它也只能访问静态数据成员 声

15、明为公有,则可以由作用域操作符调用它: 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没有公有的拷贝

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号