石家庄在哪个省,如何进行优化,唐山电商网站建设,收费底的网站有吗今天学习的是C中的二阶构造模式#xff0c;二阶构造模式只是设计模式中的简单的模式#xff0c;是一种软件设计的方法#xff0c;并没有我们想象的那么高深#xff0c;设计模式也是一样#xff0c;只不过是一系列的设计方法#xff0c;只要我们懂得了原理#xff0c;那么…今天学习的是C中的二阶构造模式二阶构造模式只是设计模式中的简单的模式是一种软件设计的方法并没有我们想象的那么高深设计模式也是一样只不过是一系列的设计方法只要我们懂得了原理那么一切都是相通的。
回顾构造函数的回顾
关于构造函数
类的构造函数用于对象的初始化构造函数与类同名并且没有返回值构造函数在对象定义时自动被调用
问题
1.如何判断构造函数的执行结果 2.在构造函数中执行return语句会发生什么 3.构造函数执行结束是否意味着对象构造成功
下面我们以码实例来分析问题
#include stdio.hclass 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 1
t1.mj 2现在我在构造函数中加一个return语句如下
#include stdio.hclass 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 1
t1.mj 2527220很显然mj变成了一个随机数那么说明构造函数在构造对象t1时执行到return语句后就返回了并没有继续执行那么到底是不是这样的呢我们来做一个试验就知道了添加一个bool型变量来判断构造函数执行到哪里去了代码如下
#include stdio.hclass 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.hclass 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的主要来源二阶构造人为的将初始化过程分成两部分二阶构造能够确保创建的对象都是完整初始化的
想获得各种学习资源以及交流学习的加我 qq1126137994 微信liu1126137994 可以共同交流关于嵌入式操作系统C语言C语言数据结构等技术问题