第二十七课:二阶构造模式----------狄泰软件学院

一、关于构造函数

1.类的构造函数用于对象的初始化
2.构造函数与类名相同并且没有返回值
3.构造函数在对象被创建时自动被调用

二、几个问题

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

#include <iostream>
using namespace std;
class Test
{
    int mi;
    int mj;
public:
    Test(int i, int j)
    {
        mi = i;

        return;//编译通过证明合法,执行了return语句,后面的语句不会再执行

        mj = j;

    }
    int getI()
    {
        return mi;
    }
    int getJ()
    {
        return mj;
    }

};

int main()
{  
    Test t1(1, 2); //对象成功诞生了,虽然构造函数除了问题  
    cout<<"t1.mi = "<<t1.getI()<<endl;//打印1
    cout<<"t1.mj = "<<t1.getJ()<<endl;//打印随机值   
    return 0;
}

答案:
1.没有方法判断构造函数的执行结果
2.构造函数可以有return语句,执行return语句后立即返回,构造函数结束
3.构造函数的结束并不意味着对象创建的完成

解决方法一:增加一个状态判断的变量mStatus

#include <iostream>
using namespace std;
class Test
{
    int mi;
    int mj;
    bool mStatus;
public:
    Test(int i, int j) : mStatus(false)//先初始化为false
    {
        mi = i;

      //  return;

        mj = j;

        mStatus = true;//在构造函数结束的位置设置为true
    }
    int getI()
    {
        return mi;
    }
    int getJ()
    {
        return mj;
    }
    int status()
    {
        return mStatus;
    }
};

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

    if( t1.status() )
    {
        cout<<"t1.mi = "<<t1.getI()<<endl;
        cout<<"t1.mj = "<<t1.getJ()<<endl;

    }

    return 0;
}

三、再谈构造函数

1.只提供自动初始化成员变量的机会
2.不能保证初始化逻辑一定成功
3.执行return语句后构造函数立即结束
所以说构造函数能决定对象的初始化状态而不是对象的产生,即使构造函数没有执行完全也不影响对象的产生

四、半成品对象:

1.初始化操作不能按照预期完成而得到的对象
2.半成品对象是合法的c++对象,也是bug的重要来源
危害举例:
在之前的数组类里面,构造函数中申请内存空间,但不一定能申请成功

Array::Array(int length)
{
    m_length = length;
    m_poiter = new int[m_length];//这里申请了内存空间很有可能不成功,得到m_poiter = 0;就会产生半成品对象;但也不会每次都不成功,所以也不可能每次都产生半成品对象
    if(m_poiter)
    {
        for(int i = 0; i < m_length; i++)
           {
            m_poiter[i] = 0;
        }
    }

}

在类的使用者这边:

int main()
{
    Array array(5);
    cout << array.get_length()<<endl;//在这里肯定会打印5,自然认为对象已正确构建
    for(int i = 0; i < array.get_length(); i++)
    {
        array.set_data(i, i+1);//但实际时内存没有申请成功,这里就会产生段错误,而当内存成功申请的时候这里又可以正常运行,这种bug非常难以调试
    }
}

五、解决方案二:二阶构造模式

工程开发中的构造过程可分为:
1.资源无关的初始化操作(不可能出现异常情况的操作)
2.申请系统资源的操作
3.两个构造函数放在私有位置,外界不能直接访问,因此需要定义一个public的对象创建函数

#include <iostream>
using namespace std;
class TwoPhaseCons 
{
private:
    TwoPhaseCons() // 第一阶段构造函数
    {   
    }
    bool construct() // 第二阶段构造函数
    { 
        return true; 
    }
public:
    static TwoPhaseCons* NewInstance(); // 对象创建函数,定义成static的原因是可以直接通过类名来访问
};

TwoPhaseCons* TwoPhaseCons::NewInstance() 
{
    TwoPhaseCons* ret = new TwoPhaseCons();

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

    return ret;
}


int main()
{
    TwoPhaseCons* obj = TwoPhaseCons::NewInstance();

    cout<<"obj = "<<obj<<endl;

    delete obj;

    return 0;
}

改写数组类:

arrar.h:
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include<iostream>
class Array
{
private:
    int m_length;
    int *m_poiter;
    Array(int length);
    Array(const Array& obj);
    bool construct();
public:
    int get_length();
    bool set_data(int index, int data);
    bool get_data(int index, int& data);    
    static Array* NewInsrance(int length);
    ~Array();
};
#endif
array.cpp:
#include"array.h"
Array::Array(int length)
{
    m_length = length;      
}
bool Array::construct()
{
    bool ret = true;
    m_poiter = new int[m_length];
    if(m_poiter)
    {
        for(int i = 0; i < m_length; i++)
           {
            m_poiter[i] = 0;
        }
    }
    else
    {
        ret = false;
    }
    return ret;
}

Array*  Array::NewInsrance(int length)
{
    Array* ret = new Array(length);
    if(!(ret && ret->construct()))
    {
        delete ret;
        ret = NULL;     
    }
    return ret;
}

int Array::get_length()
{
    return m_length;
}

bool Array::set_data(int index, int data)
{
    bool ret = ((0 <= index)&&(index<get_length()));
    if(ret)
    {
        m_poiter[index] = data;
    }
    return ret; 
}

bool Array::get_data(int index, int& data)
{
    bool ret = ((0<=index) && (index<get_length()));
    if(ret)
    {
        data = m_poiter[index];
    }
    return ret;
}

Array::~Array()
{
    delete[] m_poiter;
}
main.cpp:
#include"array.h"
using namespace std;
int main()
{
    Array* array = Array::NewInsrance(5);
    cout << array->get_length()<<endl;
    cout << endl;
    for(int i = 0; i < array->get_length(); i++)
    {
        array->set_data(i, i+1);
    }

    for(int i = 0; i < array->get_length(); i++)
    {
        int data = 0;
        if(array->get_data(i, data))
        {
            cout << data << endl;
        }
    }
    delete array;
    return 0;
}

小结:

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质?你是否想成为一名资深开发人员,想开发别人做不了的高性能程序?你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹? 那么C++就是你个人能力提升,职业之路进阶的不二之选。【程特色】 1.程共19大章节,239时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》程。【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署;2.吊打一切关于C++的笔试面试题;3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【程设计】 本程包含3大模块基础篇本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。进阶篇本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。提升篇:本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值