目录
构造函数回顾
深入思考
实验
构造函数的真相
半成品对象
引入二阶构造设计模式
设计理念
二阶构造设计模式图
二阶构造示例
完整demo
小结
构造函数回顾
- 类的构造函数用于对象的初始化。
- 构造函数与类同名并且没有返回值。
- 构造函数在对象定义时自动被调用
深入思考
- 如何判断构造函数的执行结果?
- 在构造函数中执行 return 语句会发生什么?
- 构造函数执行结束是否意味着对象构造成功?
实验
test.cpp
#include <stdio.h>class Test
{private: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;
}
编译运行,实验结果符合预期。
delphi@delphi-vm:~/c_c++$ g++ test.cpp -o test.out
delphi@delphi-vm:~/c_c++$ ./test.out
t1.mi = 1
t1.mj = 2
接下来在构造函数中,加入 return语句,实验结果如下所示:
test.cpp
#include <stdio.h>class Test
{private: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;
}
编译运行,实验结果如下,可以看到 mj的值为随机数了。
delphi@delphi-vm:~/c_c++$ g++ test.cpp -o test.out
delphi@delphi-vm:~/c_c++$ ./test.out
t1.mi = 1
t1.mj = 12783604
以上结果,可以看到:构造函数出现问题了,但是对象依旧诞生了,那么这个对象是一个合法的对象吗?
构造函数的真相
- 构造函数只提供自动初始化成员变量的机会。
- 构造函数不能保证初始化逻辑一定会成功。
- 执行 return 语句后构造函数立即结束。
- 构造函数能决定的只是对象的初始状态,而不能决定对象是否诞生。
半成品对象
- 初始化操作不能按照预期完成而得到的对象。
- 半成品对象是合法的C++对象,也是Bug的重要来源。
引入二阶构造设计模式
设计理念
工程开发中的构造过程可以分为:
一:资源无关的初始化操作
不可能出现异常情况的操作
二:需要使用系统资源的操作
可能出现异常情况,如:内存申请,访问文件
二阶构造设计模式图
从设计层面,将构造过程一分为二,第一阶段的构造做资源无关的操作,第二阶段做资源申请的操作。用二阶设计模式要么产生一个完整合法的C++对象,要么直接返回NULL,不会产生一个半成品的C++对象。
二阶构造示例
class TwoPhaseCons
{private:TwoPhaseCons(){ //第一阶段的构造函数}bool construct(){ //第二阶段的构造函数}public:static TwoPhaseCons* NewInstance(); //创建对象函数
};
TwoPhaseCons* TwoPhaseCons::NewInstance()
{TwoPhaseCons* ret = new TwoPhaseCons();//如果第二阶段构造失败,返回NULLif(!(ret && ret->construct())){delete ret;ret = NULL;}return ret;
}
完整demo
#include <stdio.h>class TwoPhaseCons
{private:TwoPhaseCons() //第一阶段的构造函数{ //做资源无关的初始化的操作}bool construct() //第二阶段的构造函数{ //做内存申请、打开文件的操作return true;}public:static TwoPhaseCons* NewInstance(); //创建对象函数
};TwoPhaseCons* TwoPhaseCons::NewInstance()
{TwoPhaseCons* ret = new TwoPhaseCons();//如果第二阶段构造失败,返回NULLif(!(ret && ret->construct())){delete ret;ret = NULL;}return ret;
}int main(int argc,char* argv[])
{TwoPhaseCons* obj = TwoPhaseCons::NewInstance();printf("obj = %p\n",obj);delete obj;return 0;
}
小结
- 构造函数只能够决定对象的初始化状态。
- 构造函数中初始化操作的失败不影响对象的诞生。
- 初始化不完全的半成品对象是Bug的重要来源。
- 二阶构造人为的将初始化过程分为两部分。
- 二阶构造能够确保创建的对象都是完整初始化的。