丘北县 大竹县 抚远县 溆浦县 靖远县 克东县 高青县 江西省 枞阳县 玉山县 宜丰县 扎鲁特旗 巴青县 夏邑县 易门县 柘荣县

文章导航软件下载单机游戏安卓资源苹果资源

pc软件新闻网络操作系统办公工具编程服务器软件评测

安卓新闻资讯应用教程刷机教程安卓游戏攻略tv资讯深度阅读综合安卓评测

苹果ios资讯苹果手机越狱备份教程美化教程ios软件教程mac教程

单机游戏角色扮演即时战略动作射击棋牌游戏体育竞技模拟经营其它游戏游戏工具

网游cf活动dnf活动lol周免英雄lol礼包

手游最新动态手游评测手游活动新游预告手游问答

您的位置:单机游戏角色扮演 → 怪物猎人世界新装备介绍 怪物猎人世界新装备新系统一览

行尸走肉第三季_第4课 - 顶层父类的创建

标签:压缩空气 广东麻将如何摸牌

在开始创建顶层父类之前,先补充两点知识,主要是为了解释为什么需要顶层父类,以及顶层父类在DTLib中的作用。

1. 软件架构实践经验

在面向对象软件架构实践中,总结出了以下三条经验:

- 尽量使用单重继承的方式进行系统设计

- 尽量保持系统中只存在单一的继承树

- 尽量使用组合关系代替继承关系

但不幸的是:

- C++语言的灵活性使得代码中可以存在多个继承树

- C++编译器的差异使得同样的代码可能表现不同的行为,举个例子,new操作如果失败会发生什么?

2. new操作失败会发生什么

【常见的动态内存分配代码】

 1 /*C代码*/
 2 int *p = (int *)malloc(10 * sizeof(int));
 3 
 4 if (p != NULL)
 5 {
 6     //......
 7 }
 8 
 9 /*C++代码*/
10 int *p = new int(10);
11 
12 if (p != NULL)
13 {
14     //......
15 }

【必须知道的事实】

- malloc函数申请失败时返回NULL

- new申请失败时,根据编译器的不同,其结果可能为:

1.返回NULL(早期C++编译器)

2.抛出std::bad_alloc异常(现代C++编译器大多采取这种结方式)

【如何跨编译器统一new的行为,提高代码移植性】

可以考虑的解决方案有:

- 类层次范围:重载new/delete,不抛出任何异常。

- 单次动态内存分配:使用nothrow参数,指明不抛出异常。

3. 顶层父类Object设计

【创建Object类的意义】

- 遵循经典设计准则,DTLib中所有数据结构类都继承自Object,保证单一继承树

- 在Object类中重载new/delete,统一动态内存申请的行为,提高代码移植性

【接口定义】

 1 #ifndef OBJECT_H
 2 #define OBJECT_H
 3 
 4 namespace DTLib
 5 {
 6 
 7 class Object
 8 {
 9 public:
10     void *operator new(unsigned int size) throw();
11     void operator delete(void *p);
12     void *operator new[](unsigned int size) throw();
13     void operator delete[](void *p);
14     virtual ~Object() = 0;
15 };
16 
17 }
18 
19 #endif // OBJECT_H

【接口实现】

考虑到malloc()申请内存失败是固定返回NULL值,因此new和new[]的重载实现为调用malloc(),delete和delete[]的重载实现为调用free()。

 1 #include "Object.h"
 2 #include <cstdlib>
 3 
 4 namespace DTLib
 5 {
 6 
 7 void *Object::operator new(unsigned int size) throw()
 8 {
 9     return malloc(size);
10 }
11 
12 void Object::operator delete(void *p)
13 {
14     free(p);
15 }
16 
17 void *Object::ope钢之炼金术师_2018年最新新闻网rator new[](unsigned int size) throw()
18 {
19     return malloc(size);
20 }
21 
22 void Object::operator delete[](void *p)
23 {
24     free(p);
25 }
26 
27 Object::~Object()火力少年王_2018年最新新闻网
28 {
29 
30 }
31 
32 }

需要注意的是,重载的new、delete仅在同时满足以下条件时适用:
1.使用了DTLib命名空间using namespace DTLib;
2.动态申请Object的子类对象Test *obj = new Test(); //class Test : public Object

【测试示例】

先在new/delete、new[]/delete[]的重载函数中添加一行测试代码:

 1 void *Object::operator new(unsigned int size) throw()
 2 {
 3     cout << "Object::operator new: " << size << endl;
 4     return malloc(size);
 5 }
 6 
 7 void Object::operator delete(void *p)
 8 {
 9     cout << "Object::operator delete: " << p << endl;
10     free(p);
11 }
12 
13 void *Object::operator new[](unsigned int size) throw()
14 {
15     cout << "Object::operator new[]: " << size << endl;
16     return malloc(size);
17 }
18 
19 void O青帝_2018年最新新闻网bject::operator delete[](void *p)
20 {
21     cout << "Object::operator delete[]: " << p << endl;
22     free(p);
23 }

然后编写main.cpp测试代码:

 1 #include "Object.h"
 2 #include <iostream>
 3 
 4 using namespace DTLib;
 5 using namespace std;
 6 
 7 class Test1 : public Object
 8 {
 9 public:
10     int i;
11     int j;
12 };
13 
14 class Test2 : public Test1
15 {
16 public:
17     int k;
18 };
19 
20 int main()
21 玛莎拉蒂_2018年最新新闻网{ 
22     Test1 *obj1 = new Test1;
23     Test2 *obj2 = new Test2;
24 
25     cout << "obj1 = " << obj1 << endl;
26     cout << "obj2 = " << obj2 << endl;
27 
28     delete obj1;
29     delete obj2;
30 
31     cout << endl;
32 
33     Test1 *obj3 = new Test1[10];
34     Test2 *obj4 = new Test2[10];
35 
36     cout << "obj3 = " << obj3 << endl;
37     cout << "obj4 = " << obj4 << endl;
38 
39     delete[] obj3;
40     delete[] obj4;
41 
42     return 0;
43 }

运行结果:

PS:测试结果显示obj3和obj4的size分别为124和164,都比理论值多了4字节,这里引用https://blog.csdn.net/hazir/article/details/21413833一文中的部分内容进行解释。

如何申请和释放一个数组?

我们经常要用到动态分配一个数组,也许是这样的:

string *psa = new string[10];      //array of 10 empty strings
int *pia = new int[10];           //array of 10 uninitialized ints

上面在申请一个数组时都用到了new []这个表达式来完成,按照我们上面讲到的 new 和 delete 知识,第一个数组是 string 类型,分配了保存对象的内存空间之后,将调用 string 类型的默认构造函数依次初始化数组中每个元素;第二个是申请具有内置类型的数组,分配了存储 10 个 int 对象的内存空间,但并没万国_2018年最新新闻网有初始化。

如果我们想释放空间了,可以用下面两条语句:

delete [] psa;
delete [] pia;

都用到delete []表达式,注意这地方的 [] 一般情况下不能漏掉!我们也可以想象这两个语句分别干了什么:第一个对 10 个 string 对象分别调用析构函数,然后再释放掉为对象分配的所有内存空间;第二个因_2018年最新新闻网为是内置类型不存在析构函数,直接释放为 10 个 int 型分配的所有内存空间。

这里对于第一种情况就有一个问题了:我们如何知道 psa 指向对象的数组的大小?怎么知道调用几次析构函数?

这个问题直接导致我们需要在 new [] 一个对象数组时,需要保存数组的维度,C++ 的做法是在分配数组空间时多分配了 4 个字节的大小,专门保存数组的大小,在 delete [] 时就可以取出这个保存的数,就知道了需要调用析构函数多少次了

还是用图来说明比较清楚,我们定义了一个类 A,但不具体描述类的内容,这个类中有显示的构造函数、析构函数等。那么 当我们调用

class A *pAa = new A[3];

时需要做的事情如下:

从这个图中我们可以看到申请时在数组对象的上面还多分配了 4 个字节用来保存数组的大小,但是最终返回的是对象数组的指针,而不是所有分配空间的起始地址。

这样的话,释放就很简单了:

delete [] pAa;

这里要注意的两点是:

  • 调用析构函数的次数是从数组对象指针前面的 4 个字节中取出;
  • 传入operator delete[]函数的参数不是数组对象的指针 pAa,而是 pAa 的值减 4。

4. 异常类改进

根据所设计的顶层父类Object,对上次创建的异常类进行如下改进:

【改进点一】

Exception类继承自Object类class Exception : public Object,使得在堆空间创建异常类对象失败时,返回NULL指针。

【改进点二】

新增InvalidOperationException非法操作异常类,当类的成员函数被调用时,如果状态不正确(如一些成员函数在类对象刚初始化时不允许使用)则抛出异常

 1 /*
 2  * 非法操作异常:类的成员函数被调用时,如果状态不正确(如一些成员函数在类对象刚初始化时不允许使用)则抛出异常
 3 */
 4 class InvalidOperationException : public Exception
 5 {
 6 public:
 7     InvalidOperationException() : Exception(0) { }
 8     InvalidOperationException(const char *message) : Exception(message) { }
 9     InvalidOperationException(const char *file, int line) : Exception(file, line) { }
10     InvalidOperationException(const char *message, const char *file, int line) : Exception(message, file, line) { }
11 
12     InvalidOperationException(const InvalidOperationException& e) : Exception(e) { }
13     InvalidOperationException &operator = (const InvalidOperationException &e)
14     {
15         Exception::operator =(e);
16         return *this;
17     }
18 };

5. DTLib的开发方式和注意事项

  1. 迭代开发:每次完成一个小的目标,持续开发,最终打造可复用类库
  2. 单继承,单一继承树:所有类都继承自Object,统一规范堆对象创建时的行为
  3. 只抛异常,不处理异常:使用THROW_EXCEPTION抛异常,提高可移植性
  4. 弱耦合性:尽量不使用std标准库中的类和函数,提高可移植性

注:本文整理于狄泰《数据结构开发实战教程》课程内容

当前文章:http://86l-skjdiaj-com.liecellular.cn/5ffa/43489_153783.html

发布时间:2019-10-19 03:54:05

银河优越会会员申请  澳门银河www66356com  银河国际手机网址2949  澳门银河娱乐送彩金网站  澳门银河娱乐送彩金网站  澳门银河yh7788.bet  919银河优越会  澳门银河送彩金夏威夷基拉韦厄火山爆发熔岩流出  澳门银河手机网站  澳门银河娱乐场yh163am.com  

相关阅读 彭博社:蚂蚁金服融资目标据悉提高至120亿美元滴滴司机猥亵儿童获刑,最高法:网约平台应加大身份识别力度全尺寸特价/凉而不冰,牡丹仙子印花冰丝凉席三件套39.9元(30元券)网媒记者西藏山南行:记录雪域变迁,描绘边疆新颜谷歌计划在10月发布至少两款新Pixel,或由富士康代工上海一民办幼儿园多名幼儿面部被划伤 涉事老师被刑拘园长被免职哈罗单车回应日订单量激增:算不清的数学题区块链安全公司派盾科技获高榕资本数千万元天使轮融资

文章评论
发表评论

热门文章 问答:为什么国行手机是两脚插头,港行就是三脚插头?微软Lumia 950 XL成功安装Windows 10 ARM64教程指南发布乐视网收到乐融致新等子公司估值报告 乐融致新估值96.6亿元解读互联网女皇报告:腾讯和今日头条必有一战,盒马鲜生们值得看好

最新文章 研究公司:自2010年来苹果App Store总收入已达1300亿美元MPV也玩纯电,奔驰要靠电气化武装到牙齿 城乡居民医保“钱袋子”购买力将提升日版电影《那些年 我们一起追过的女孩》公开预告 斋藤飞鸟演绎青春恋情迅雷9.5.63.2128 PC测试版下载:新增“迅雷口令”功能传微软将公布新《光环》和新《战争机器》等游戏

人气排行 社科院研究生院工商学院院长助理杨小科:依托大数据优势提升价值清水加上这几种食物 效果好的没得夸AMD正研发3款7nm产品:今年采样,有望2019年上市江西新增林下种植面积63.95万亩 森林药材19.18万亩[最后24小时]最大618元神券,京东618购物节必领京喜红包江西新增林下种植面积63.95万亩 森林药材19.18万亩要进行星际移民,太空飞船需考虑哪些要素?“互联网女皇”报告:应高度重视隐私安全,但不能妨碍创新和进步