第27课 二阶构造模式

本文内容取自于对狄泰学院 唐佐林老师 C++深度解析 课程的学习总结

构造函数的回顾

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

问题

  1. 如判断 构造函数 的执行结果?
  2. 在构造函数中执行 return 语句会发生什么?
  3. 构造函数执行 结束是否意味着 对象构造成功?

为什么了回答这几个问题,我们编写一个构造函数,并且构造函数中添加 return 语句

#include <stdio.h>

class Test
{
private:
    int m_i;
    int m_j;
public:
    Test(int i, int j);

    int getI();
    int getJ();
};

Test::Test(int i, int j)
    : m_i(0),m_j(0)
{
    m_i = i;

    /* 在m_j没有赋值的情况下强制返回 */
    return;

    m_j = j;
}


int Test::getI()
{
    return m_i;
}

int Test::getJ()
{
    return m_j;
}

int main(void)
{
    Test t1(1, 2);

    printf("t1.m_i = %d\n", t1.getI());
    printf("t1.m_j = %d\n", t1.getJ());

    return 0;
}

执行结果
在这里插入图片描述

程序第27行给构造函数使用 return 强制返回,结果是 构造 t1 对象时,t1的m_j成员变量并没有成功赋值为2,依然为初始化时的0。 m_i 成功赋值。
所以 t1 对象并没有完全构造成功,而是一个 半成品对象

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

构造函数能决定的 只是对象的初始状态
而不是对象的诞生!!!



半成品对象

半成品对象 的概念
  • 初始化操作不能按照预期完成而得到的对象
  • 半成品对象是 合法的C++对象,也是 Bug 的重要来源

为了说明半成品对象的危害,我们来做个实验
首先实现一个数组类,实验构造数组长度,设置数组元素值,获取数据元素值,获取数组长度功能。

Array.h

#ifndef __ARRAY_H__
#define __ARRAY_H__


class Array{
private:
    int m_len;
    int *m_pointer;

public:
    Array(int len);
    bool setArrayVal(int index, int val);
    bool getArrayVal(int index, int& val);
    int getArrayLen();
};




#endif

Array.cpp

#include "Array.h"


Array::Array(int len)
{
    m_pointer = new int[len];

    for(int i=0; i<len; i++)
        m_pointer[i] = 0;

    m_len = len;
}


bool Array::setArrayVal(int index, int val)
{
    bool ret = (index >=0) && (index < m_len);

    if(ret)
        m_pointer[index] = val;

    return ret; 
}


bool Array::getArrayVal(int index, int& val)
{
    bool ret = (index >= 0) && (index < m_len);

    if(ret)
        val = m_pointer[index];

    return ret;
}


int Array::getArrayLen()
{
    return m_len;
}

main.cpp

#include "Array.h"
#include <stdio.h>


int main(void)
{
    Array a(5);

    for(int i=0; i<a.getArrayLen(); i++)
    {
        a.setArrayVal(i, i+1);
    }

    for(int i=0; i<a.getArrayLen(); i++)
    {
        int val = 0;
        a.getArrayVal(i, val);
        printf("%d : %d\n", i, val);
    }


    return 0;
}

运行结果:
在这里插入图片描述

实验结果:成功的实现了我们预期的结果,构造了一个长度为5的数组对象,并对该对象元素进行赋值。

现在,我们来人为制造半成品对象,假设构造对象时构造函数中 申请数组堆内存失败,会发生什么情况
在这里插入图片描述
运行结果
在这里插入图片描述

实验结论:由于堆内存申请失败,设置数组元素值时操作空指针导致程序段错误

因为构造函数没有返回值,我们无法获知堆内存申请的结果,为了避免这种情况
我们增加了二阶构造模式




二阶构造

工程开发中的 构造过程 可分为

1.资源无关 的初始化操作
   不可能出现异常情况 的操作
2. 需要 使用系统资源 的操作
   可能出现异常情况,如:内存申请,访问文件等


二阶构造过程

在这里插入图片描述

二阶构造示例
在这里插入图片描述
对象创建函数示例
在这里插入图片描述
下面,我们将刚才的代码做二阶构造改写
1.在Array.h中增加二阶构造接口
在这里插入图片描述
在Array.cpp中实现二阶构造接口
在这里插入图片描述
在main.cpp中调用对象创建函数进行对象的创建
在这里插入图片描述

运行结果
在这里插入图片描述

利用 二阶构造模式 可以对对象创建结果进行判断,避免生成半成品对象而导致程序异常的发生



小结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lzg2021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值