1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【C++深度剖析教程4】C++的二阶构造模式

【C++深度剖析教程4】C++的二阶构造模式

时间:2020-09-29 14:40:10

相关推荐

【C++深度剖析教程4】C++的二阶构造模式

今天学习的是C++中的二阶构造模式,二阶构造模式只是设计模式中的简单的模式,是一种软件设计的方法,并没有我们想象的那么高深,设计模式也是一样,只不过是一系列的设计方法,只要我们懂得了原理,那么一切都是相通的。

回顾:构造函数的回顾

关于构造函数:

类的构造函数用于对象的初始化构造函数与类同名并且没有返回值构造函数在对象定义时自动被调用

问题:

1.如何判断构造函数的执行结果?

2.在构造函数中执行return语句会发生什么?

3.构造函数执行结束是否意味着对象构造成功?

下面我们以码实例来分析问题:

#include <stdio.h>class Test{int mi;int mj;public:Test(int i, int j){mi = i;mj = j;}int getI(){return mi;}int getJ(){return mj;}};int main(){Test t1(1, 2);printf("t1.mi = %d\n", t1.getI());printf("t1.mj = %d\n", t1.getJ());return 0;}

这就是一个普普通通的代码,用来初始化两个变量的。编译输出结果为:

t1.mi = 1t1.mj = 2

现在我在构造函数中加一个return语句如下:

#include <stdio.h>class Test{int mi;int mj;public:Test(int i, int j){mi = i;return;mj = j;}int getI(){return mi;}int getJ(){return mj;}};int main(){Test t1(1, 2);printf("t1.mi = %d\n", t1.getI());printf("t1.mj = %d\n", t1.getJ());return 0;}

执行结果为:

t1.mi = 1t1.mj = 2527220

很显然mj变成了一个随机数,那么说明构造函数在构造对象t1时,执行到return语句后就返回了,并没有继续执行,那么到底是不是这样的呢?我们来做一个试验就知道了,添加一个bool型变量来判断构造函数执行到哪里去了,代码如下:

#include <stdio.h>class Test{int mi;int mj;bool mStatus;public:Test(int i,int j) : mStatus(false){mi = i;return;mj = j;mStatus = true;}int getI(){return mi;}int getJ(){return mj;}int status(){return mStatus;}};int main(){Test t1(1,2);if(t1.status()){printf("t1.mi = %d\n", t1.getI());printf("t1.mj = %d\n", t1.getJ());} return 0;}

编译执行后,没有输出结果,说明构造函数没有将对象初始化完成。

由此我们可以得出几条结论:

构造函数:

只提供自动初始化成员变量的机会不能保证初始化逻辑一定成功执行return 语句后构造函数立即结束

从而我们知道,构造函数能决定的只是对象的初始状态,而不是对象的诞生!!!,上面的代码我们加了return语句后,t1这个对象就没有真正的被完全构造,所以不能正常使用这个对象。

这样的对象,我们叫它:半成品对象.

半成品对象的概念:

初始化操作不能按照预期完成二得到的对象

半成品对象是合法的C++对象,但是同时它也是Bug的重要来源

一般企业中最难以调试的Bug,一是野指针(后面文章会写),其次就是这个半成品对象带来的Bug。

二阶构造

那么我们该如何避免这样的Bug呢?下面就引出二阶构造的含义:

工程开发中的构造过程可分为 资源无关的初始化操作

*不可能出现异常情况的操作需要使用系统资源的操作

*可能出现异常情况,如:内存申请,访问文件

二阶构造大体流程:

实例代码如下:

#include <stdio.h>class TwoPhaseCons {private:TwoPhaseCons() // 第一阶段构造函数{}bool construct() // 第二阶段构造函数{return true; }public:static TwoPhaseCons* NewInstance(); // 对象创建函数};TwoPhaseCons* TwoPhaseCons::NewInstance() {TwoPhaseCons* ret = new TwoPhaseCons();// 若第二阶段构造失败,返回 NULL if( !(ret && ret->construct()) ) {delete ret;ret = NULL;}return ret;}int main(){TwoPhaseCons* obj = TwoPhaseCons::NewInstance();printf("obj = %p\n", obj);delete obj;return 0;}

我们来分析一下以上代码:

二阶构造示例:

class TwoPhaseCons {private:TwoPhaseCons() // 第一阶段构造函数{}bool construct() // 第二阶段构造函数{return true; }public:static TwoPhaseCons* NewInstance(); // 对象创建函数};

第一阶段构造函数与第二阶段构造函数放到private里面了,外部无法调用。

但是在public中,定义的是static 型的NewInstance函数,返回TwoPhaseCons类型的对象,那么通过它就可以调用private里面的构造函数。例如在NewInstance函数里可以有如下代码:TwoPhaseCons* ret = new TwoPhaseCons();,因为处于NewInstance内部,所以它可以调用构造函数。

TwoPhaseCons* TwoPhaseCons::NewInstance() {TwoPhaseCons* ret = new TwoPhaseCons();// 若第二阶段构造失败,返回 NULL if( !(ret && ret->construct()) ) {delete ret;ret = NULL;}return ret;}

TwoPhaseCons* ret = new TwoPhaseCons();//调用第一阶段的构造函数,做一些初始化操作,不会引起异常的操作

通过判断语句:if( !(ret && ret->construct()) )可以判断两个阶段的构造过程是否都没有错误。

而在main函数中有一句话:TwoPhaseCons* obj = TwoPhaseCons::NewInstance();这是调用NewInstance()函数创建obj 对象,因为构造函数TwoPhaseCons为private类型,所以想创建对象,必须用public中的静态创建函数:static TwoPhaseCons* NewInstance(); // 对象创建函数而不能像之前那样直接用构造函数创建对象了如:TwoPhaseCons obj;

上面的程序的运行结果为:

obj = 0x8a0d008

这说明,我们在上面合法的创建看了对象obj。

同时我们也可以看出,用了二阶构造模式后,对象只能在堆空间上进行构造而不能在栈空间上构造,这样好么?答案是肯定的,因为工程上的对象往往是巨大的,一般都会放到堆空间上进行构造。

总结:

构造函数只能决定对象的初始化状态构造函数中初始化操作的失败不影响对象的诞生初始化不完全的半成品对象是Bug的主要来源二阶构造人为的将初始化过程分成两部分二阶构造能够确保创建的对象都是完整初始化的

想获得各种学习资源以及交流学习的加我:

qq:1126137994

微信:liu1126137994

可以共同交流关于嵌入式,操作系统,C++语言,C语言,数据结构等技术问题!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。