C++解析(15):二阶构造模式
0.目录
1.构造函数与半成品对象
2.二阶构造
3.小结
1.构造函数与半成品对象
关于构造函数:
- 类的构造函数用于对象的初始化
- 构造函数与类同名并且没有返回值
- 构造函数在对象定义时自动被调用
问题:
- 如何判断构造函数的执行结果?
- 在构造函数中执行return语句会发生什么?
- 构造函数执行结束是否意味着对象构造成功?
(没有办法判断构造函数的执行结果,构造函数执行结束不意味着对象构造成功)
用一个状态来表示对象是否构造成功:
#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语句后构造函数立即结束
构造函数能决定的只是对象的初始状态,而不是对象的诞生!!
半成品对象的概念:
- 初始化操作不能按照预期完成而得到的对象
- 半成品对象是合法的C++对象,也是Bug的重要来源
2.二阶构造
工程开发中的构造过程可分为:
- 资源无关的初始化操作
- 不可能出现异常情况的操作
- 需要使用系统资源的操作
- 可能出现异常情况,如:内存申请,访问文件
二阶构造:

二阶构造示例一:

二阶构造示例二:

示例代码:
#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;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
obj = 0xd4f010
若是二阶构造失败了呢?
#include <stdio.h>
class TwoPhaseCons
{
private:
TwoPhaseCons() // 第一阶段构造函数
{
}
bool construct() // 第二阶段构造函数
{
return false;
}
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;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
obj = (nil)
会返回一个空。
使用二阶构造模式后,对象只能在堆空间上创建,不能在栈上产生了。这恰恰是工程里面最重要的一个决定,因为在工程中,对象往往是比较巨大的,不适合放在栈空间当中,都应该放到堆空间里面去。
3.小结
- 构造函数只能决定对象的初始化状态
- 构造函数中初始化操作的失败不影响对象的诞生
- 初始化不完全的半成品对象是Bug的重要来源
- 二阶构造人为的将初始化过程分为两部分
- 二阶构造能够确保创建的对象都是完整初始化的
C++解析(15):二阶构造模式的更多相关文章
- C++之二阶构造模式
前言:C++中经常会因为调用系统资源失败导致出现BUG,所以在类调用构造函数需要分配系统资源时会出现BUG,从而导致类对象虽然被创建,但是只是个半成品,为了避免这种情况需要使用二阶构造模式 二阶构造模 ...
- C++ 二阶构造模式
1.如何判断构造函数的执行结果? 构造函数没有返回值,所以不能通过返回值来判断是构造函数是否构造成功. 如果给构造函数强行加入一个返回值,用来表示是否构造成功.这样确实能够反映出构造的结果,但是不够优 ...
- 14.C++-二阶构造模式、友元(详解)
首先回顾以前所学的构造函数 类的构造函数用于对象的初始化 构造函数与类同名并且没有返回值 构造函数在定义时被自动调用 由于构造函数没有返回值不能判断执行结果,所以不能保证初始化对象能否成功 比如: c ...
- Spark Streaming揭秘 Day34 解析UI监听模式
Spark Streaming揭秘 Day34 解析UI监听模式 今天分享下SparkStreaming中的UI部分,和所有的UI系统一样,SparkStreaming中的UI系统使用的是监听器模式. ...
- 第15章 迭代器模式(Iterator Pattern)
原文 第15章 迭代器模式(Iterator Pattern) 迭代器模式(Iterator Pattern) 概述: 在面向对象的软件设计中,我们经常会遇到一类集合对象,这类集合对象的内部结构 ...
- 【省带宽、压成本专题】深入解析 H.265 编码模式,带你了解 Apple 全面推进 H.265 的原因
过去几年,又拍云一直在点播.直播等视频应用方面潜心钻研,取得了不俗的成果.我们结合点播.直播.短视频等业务中的用户场景,推出了"省带宽.压成本"系列文章,从编码技术.网络架构等角度 ...
- JSON.stringify()方法是将一个javascript值(对象或者数组)转换成为一个JSON字符串;JSON.parse()解析JSON字符串,构造由字符串描述的javascript值或对象
JSON.stringify()方法是将一个javascript值(对象或者数组)转换成为一个JSON字符串:JSON.parse()解析JSON字符串,构造由字符串描述的javascript值或对象
- Java设计模式(15)备忘录模式(Memento模式)
Memento定义:memento是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态. Memento模式相对也比较好理解,我们看下列代码: public class ...
- javascript创建对象之函数构造模式和原型模式结合使用(四)
创建自定义类型的常见方式就是组合使用构造函数模式与原型模式一起使用. 构造函数模式用于定义实例对象的特有的部分(属性和方法),原型模式用于定义共享的部分. 这样最大限度的节省了内存的开销. funct ...
随机推荐
- 【索引】MySQL索引
一.索引的定义及作用 1. 二.索引的创建及删除 1.1查看表的索引 show index from tblname; 1.2.创建索引 1.22创建普通索引 ALTER TABLE `table_n ...
- 区块链技术:每位CEO都应了解
区块链技术有可能成为一项广泛应用的突破性技术,像蒸汽机.电力或因特网那 样,改变整个社会和经济的运行方式. 对企业而言,信任至关重要.今天,我们基于信任,将钱存放在银行,通过电商企业 网购产品,并且依 ...
- 原生 js 简单实现 Promise
写在思否,欢迎各位大佬给出建议: https://segmentfault.com/a/1190000018530433
- 关于scrum敏捷测试
关于scrum的一些定义 敏捷软件开发方法是一种把新增功能通过较小的循环逐步迭代添加到项目中(的项目管理方法),工作是由自我组织的团队以高效合作的方式拥抱和适应变化来保证客户需求被真正满足的方式来完成 ...
- Lua学习笔记(2): 流程控制与循环以及初涉迭代器
条件判断语句 --if...语句 if (表达式) then --表达式为1时执行的语句 end --if...else语句 if (表达式) then --表达式为1时执行的语句 else --表达 ...
- vim—多行注释、取消多行注释
多行注释 命令模式: (1)将光标放在要注释的行首,按下组合键ctrl + v ,然后按上下键选取要注释的行. (2)按下大i键,然后插入要注释的符号 # (3)按ESC键,退出后,就会全部注释. 取 ...
- Python异常(基础) except
为什么要异常处理机制:在程序调用层数较深时,向主调函数传递错误信息需要层层return 返回比较麻烦,用异常处理机制可以较简单的传送错误信息 什么是错误 错误是指由于逻辑或语法等导致一个程序已无法正常 ...
- Qt类继承关系图
分享两个资源,对于系统了解Qt框架的整体脉络很有帮助. Qt4类关系图+Qt5类关系图,PDF+JPG格式 [下载] Qt5类关系图(基于Qt5.1版),JPG格式[下载]
- Linux sync命令的作用分析
Sync命令 在用reboot命令启动unix系统后,系统提示出错信息,部分应用程序不能正常工作.经仔细检查系统文件,并和初始的正确备份进行比较,发现某些文件确实被破坏了,翻来覆去找不到文件遭破坏 ...
- winform default模式下和英文模式下 修改问题
1.修改控件大小.位置等属性在default模式下修改: 2.修改控件属性最好不要做鼠标拖动放大,拖动修改位置等,建议用属性栏中的数字来改变.