首页 - 网校 - 万题库 - 直播 - 雄鹰 - 团购 - 书城 - 模考 - 学习通 - 导航 - 510 -
首页考试吧网校万题库直播雄鹰510团购书城模考论坛实用文档作文大全宝宝起名
2015中考
法律硕士
2015高考
MBA考试
2015考研
MPA考试
在职研
中科院
考研培训
专升本
自学考试 成人高考
四 六 级
GRE考试
攻硕英语
零起点日语
职称英语
口译笔译
申硕英语
零起点韩语
商务英语
日语等级
GMAT考试
公共英语
职称日语
新概念英语
专四专八
博思考试
零起点英语
托福考试
托业考试
零起点法语
雅思考试
成人英语三级
零起点德语
等级考试
华为认证
水平考试
Java认证
职称计算机 微软认证 思科认证 Oracle认证 Linux认证
公 务 员
导游考试
物 流 师
出版资格
单 证 员
报 关 员
外 销 员
价格鉴证
网络编辑
驾 驶 员
报检员
法律顾问
管理咨询
企业培训
社会工作者
银行从业
教师资格
营养师
保险从业
普 通 话
证券从业
跟 单 员
秘书资格
电子商务
期货考试
国际商务
心理咨询
营 销 师
司法考试
国际货运代理人
人力资源管理师
广告师职业水平
卫生资格 执业医师 执业药师 执业护士
会计从业资格
基金从业资格
统计从业资格
经济师
精算师
统计师
会计职称
法律顾问
ACCA考试
初级会计职称
资产评估师
高级经济师
注册会计师
高级会计师
美国注册会计师
审计师考试
国际内审师
注册税务师
理财规划师
一级建造师
安全工程师
设备监理师
公路监理师
公路造价师
二级建造师
招标师考试
物业管理师
电气工程师
建筑师考试
造价工程师
注册测绘师
质量工程师
岩土工程师
注册给排水
造价员考试
注册计量师
环保工程师
化工工程师
暖通工程师
咨询工程师
结构工程师
城市规划师
材料员考试
消防工程师
监理工程师
房地产估价
土地估价师
安全评价师
房地产经纪人
投资项目管理师
环境影响评价师
土地登记代理人
宝宝起名
缤纷校园
实用文档
入党申请
英语学习
思想汇报
作文大全
工作总结
求职招聘 论文下载 直播课堂
您现在的位置: 考试吧 > 计算机等级考试 > 计算机二级考试 > C加加 > 复习资料 > 正文

2015年国家计算机二级C++考试复习资料(7)

来源:考试吧 2014-12-26 14:10:12 考试吧:中国教育培训第一门户 模拟考场
考试吧整理了“2015年国家计算机二级C++考试复习资料”,提供给各位考生备考,更多考试资料请持续关注考试吧计算机等级考试频道!

  点击查看:2015年国家计算机二级C 考试复习资料汇总

  二级C++辅导笔记:类和堆

  一、构造函数和析构函数

  前面的例子已经运用了new和delete来为类对象分配和释放内存。当使用new为类对象分配内存时,编译器首先用new运算符分配内存,然后调用类的构造函数;类似的,当使用delete来释放内存时,编译器会首先调用泪的析构函数,然后再调用delete运算符。

  #include iostream.h

  class Date

  {

  int mo,da,yr;

  public:

  Date() { cout < ~Date() { cout< }

  int main()

  {

  Date* dt = new Date;

  cout < delete dt;

  return 0;

  }

  程序定义了一个有构造函数和析构函数的Date类,这两个函数在执行时会显示一条信息。当new运算符初始化指针dt时,执行了构造函数,当delete运算符释放内存时,又执行了析构函数。

  程序输出如下:

  Date constructor

  Process the date

  Date destructor

  二、堆和类数组

  前面提到,类对象数组的每个元素都要调用构造函数和析构函数。下面的例子给出了一个错误的释放类数组所占用的内存的例子。

  #include iostream.h

  class Date

  {

  int mo, da, yr;

  public:

  Date() { cout < ~Date() { cout< }

  int main()

  {

  Date* dt = new Date[5];

  cout < delete dt; //这儿

  return 0;

  }

  指针dt指向一个有五个元素的数组。按照数组的定义,编译器会让new运算符调用Date类的构造函数五次。但是delete被调用时,并没有明确告诉编译器指针指向的Date对象有几个,所以编译时,只会调用析构函数一次。下面是程序输出;

  Date constructor

  Date constructor

  Date constructor

  Date constructor

  Date constructor

  Process the date

  Date destructor

  为了解决这个问题,C++允许告诉delete运算符,正在删除的那个指针时指向数组的,程序修改如下:

  #include iostream.h

  class Date

  {

  int mo, da, yr;

  public:

  Date() { cout < ~Date() { cout< }

  int main()

  {

  Date* dt = new Date[5];

  cout < delete [] dt; //这儿

  return 0;

  }

  最终输出为:

  Date constructor

  Date constructor

  Date constructor

  Date constructor

  Date constructor

  Process the date

  Date destructor

  Date destructor

  Date destructor

  Date destructor

  Date destructor

  三、重载new和delete运算符

  前面已经介绍了如何用new和delete运算符函数来动态第管理内存,在那些例子中使用的都是全局的new和delete运算符。我们可以重载全局的new和delete运算符,但这不是好的想法,除非在进行低级的系统上或者嵌入式的编程。

  但是,在某个类的内部重载new和delete运算符时可以的。这允许一个类有它自己的new和delete运算符。当一个类需要和内存打交道时,采用这种方法来处理其中的细节,可以获得很搞的效率,同时避免了使用全局new和delete运算符带来的额外开销。因为全局堆操作时调用操作系统函数来分配和释放内存,这样效率很低。

  如果确定某个类在任何时候,其实例都不会超过一个确定的值,那么就可以一次性为类的所有实例分配足够的内存,然后用该类的new和delete运算符来管理这些内存。下面的程序说明了如何对new和delete进行重载。

  #include iostream.h

  #include string.h

  #include stddef.h

  #include new.h

  const int maxnames = 5;

  class Names

  {

  char name[25];

  static char Names::pool[];

  static bool Names::inuse[maxnames];

  public:

  Names(char* s) { strncpy(name,s,sizeof(name)); }

  void* operator new(size_t) throw(bad_alloc);

  void operator delete(void*) throw();

  void display() const { cout < };

  char Names::pool[maxnames * sizeof(Names)];

  bool Names::inuse[maxnames];

  void* Names::operator new(size_t) throw(bad_alloc)

  {

  for(int p=0; p {

  if(!inuse[p])

  {

  inuse[p] = true;

  return pool+p*sizeof(Names);

  }

  }

  throw bad_alloc();

  }

  void Names::operator delete(void* p) throw()

  {

  if(p!=0)

  inuse[((char*)p - pool)/sizeof(Names)] = false;

  }

  int main()

  {

  Names* nm[maxnames];

  int i;

  for(i=0; i {

  cout < char name[25];

  cin >> name;

  nm[i] = new Names(name);

  }

  for(i=0; i {

  nm[i]- >display();

  delete nm[i];

  }

  return 0;

  }

  上面的程序提示输入5个姓名,然后显示它们。程序中定义了名为Names的类,它的构造函数初始化对象的name值。这个类定义了自己的new和delete运算符。这是因为程序能保证不会一次使用超过maxnames个姓名,所以可以通过重载默认的new和delete运算符来提高运行速度。

  Names类中的内存池是一个字符数组,可以同时容纳程序需要的所有姓名。与之相关的布尔型数组inuse为每个姓名记录了一个true和false值,指出内存中的对应的项是否正在使用。

  重载的new运算符在内存池中寻找一个没有被使用的项,然后返回它的地址。重载的delete运算符则标记那些没有被使用的项。

  在类定义中重载的new和delete运算符函数始终是静态的,并且没有和对象相关的this指针。这是因为编译器会在调用构造函数之前调用new函数,在调用析构函数后调用delete函数。

  new函数是在类的构造函数之前被调用的。因为这时内存中还不存在类的对象而且构造函数也没有提供任何初始化值,所以它不可以访问类的任何成员。同理,delete运算符是在析构函数之后被调用的,所以它也不可以访问类的成员。

  四、异常监测和异常处理

  1.检测异常

  上面的例子还缺少必要的保护机制。比如,重载的delete运算符函数并没有检查它的参数,确认其是否落在内存池内部。如果你绝对相信自己编的程序中不会传递错误的指针值给delete运算符,那么可以省掉合法性检查以提高效率,特别是在优先考虑效率的程序中。否则应该使用预编译的条件语句。在软件的测试版本中加入这些检测,在正式的发行版本中去掉这些检查。

  2.重载new和delete中的异常处理

  上面的两个重载运算符函数都是用了异常处理。异常处理是C++的新内容之一,目前还没有讲到。在这里不必关心它是如何工作的。上面程序中,当试图分配超过内存池容量的Names缓冲区,重载的new运算符函数就会抛出异常,终止程序。

  五、重载new[]和delete[]

  对于上面的程序,假如有下面的语句:

  Names *nms=new Names[10]

  ...

  delete [] nms;

  那么,这些语句会调用全局new和delete运算符,而不是重载过的new和delete。为了重载能为对象数组分配内存的new和delete运算符,必须像下面的程序一样,对new[]和delete[]也进行重载。

  #include iostream.h

  #include string.h

  #include stddef.h

  #include new.h

  const int maxnames = 5;

  class Names

  {

  char name[25];

  static char Names::pool[];

  static bool Names::inuse[maxnames];

  public:

  Names(char* s) { strncpy(name,s,sizeof(name)); }

  void* operator new(size_t) throw(bad_alloc);

  void operator delete(void*) throw();

  void display() const { cout < };

  char Names::pool[maxnames * sizeof(Names)];

  bool Names::inuse[maxnames];

  void* Names::operator new[](size_t size) throw(bad_alloc)

  {

  int elements=size/sizeof(Names);

  int p=-1;

  int i=0;

  while((i {

  if(!inuse[i]) p=i;

  ++i;

  }

  // Not enough room.

  if ((p==-1) || ((maxnames-p) for(int x=0; x return pool+p*sizeof(Names);

  }

  void Names::operator delete[](void* b) throw()

  {

  if(b!=0)

  {

  int p=((char*)b- pool)/sizeof(Names);

  int elements=inuse[p];

  for (int i=0; i }

  }

  int main()

  {

  Names* np = new Names[maxnames];

  int i;

  for(i=0; i {

  cout < char name[25];

  cin >> name;

  *(np + i) = name;

  }

  for(i=0; idisplay();

  delete [] np;

  return 0;

  }

  重载new[]和delete[]要比重载new和delete考虑更多的问题。这是因为new[]运算符时为数组分配内存,所以它必须记住数组的大小,重载的delete[]运算符才能正确地把缓冲区释放回内存池。上面的程序采用的方法比较简单,吧原来存放缓冲区使用标志的布尔型数组换成一个整型数组,该数组的每个元素记录new[]运算符分配的缓冲区个数,而不再是一个简单的true。当delete[]运算符函数需要把缓冲区释放回内存池时,它就会用该数组来确认释放的缓冲区个数。

  相关推荐:

  各地2015年计算机等级考试报名时间汇总

  各地2015年上半年计算机等级考试费用汇总

  2015年计算机二级C++模拟练习题及答案汇总

文章责编:luoyuting  
看了本文的网友还看了
文章搜索
版权声明:如果计算机等级考试网所转载内容不慎侵犯了您的权益,请与我们联系800@exam8.com,我们将会及时处理。如转载本计算机等级考试网内容,请注明出处。
Copyright © 2004- 考试吧计算机等级考试网 All Rights Reserved 
中国科学院研究生院权威支持(北京) 电 话:010-62168566 传 真:010-62192699