第27课 二阶构造模式

1. 构造函数的回顾

(1)关于构造函数

  ①类的构造函数用于对象的初始化

  ②构造函数与类同名并且没有返回值(思考:无返回值如何判断构造函数的执行结果?)

  ③构造函数在对象定义自动被调用

【编程实验】异常的构造函数

#include <stdio.h>

class Test
{
private:
    int mi;
    int mj;
    bool mStatus;

public:
    Test(int i, int j):mStatus(false)
    {
        mi = i;

        return;//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()) //构造未完成,status为false
    {
        printf("t1.mi = %d\n", t1.getI());//i被正确初始化
        printf("t1.mj = %d\n", t1.getJ());//j为随机值
    }

    return 0;
}

(2)构造函数的真相

  ①构造函数只提供自动初始化成员变量的机会,但不能保证初始化逻辑一定成功。它只能决定对象的初始状态,而不是对象的诞生

  ②在构造函数中执行return语句后,构造函数立即结束

2. 半成品对象

(1)初始化操作不能按照预期完成而得到的对象

(2)半成品对象是合法的C++对象,也是bug的重要来源

3. 二阶构造

(1)工程开发中的构造过程

  ①资源无关的初始化操作阶段:即不会出现异常情况的操作

  ②需要使用系统资源的操作:可能出现异常,如内存申请,访问文件等。

(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;
}

【编程实验】数组类的加强

//IntArray.h

#ifndef _INTARRAY_H_
#define _INTARRAY_H_

class IntArray
{
private:
    int m_length;
    int* m_pointer;

    //将构造函数变为私有的
    IntArray(int len);
    bool construct(); //第2阶构造函数

public:
    static IntArray* NewInstance(int length);//提供创建对象的函数
    int length();
    bool get(int index, int& value);
    bool set(int index, int value);
    ~IntArray();
};

#endif

//IntArray.cpp

#include "IntArray.h"

IntArray::IntArray(int len)
{
    m_length = len;
}

bool IntArray::construct()
{
    bool ret = true;

    m_pointer = new int[m_length];

    if (m_pointer)
    {
        for(int i = 0; i<m_length; i++)
        {
            m_pointer[i] = 0;
        }
    }
    else
    {
        ret = false;
    }

    return ret;
}

IntArray* IntArray::NewInstance(int length)
{
    IntArray* ret = new IntArray(length);

    if(!(ret && ret->construct()))
    {
        delete ret;
        ret = 0;
    }

    return ret;
}

IntArray::~IntArray()
{
    if(m_pointer)
    {
        delete[] m_pointer;
    }
}

int IntArray::length()
{
    return m_length;
}

bool IntArray::get(int index, int& value)
{
   bool bRet = (0 <= index) && (index <m_length);

   if(bRet)
   {
        value = m_pointer[index];
   }

   return bRet;
}

bool IntArray::set(int index, int value)
{

   bool bRet = (0 <= index) && (index <m_length);

   if(bRet)
   {
        m_pointer[index] = value;
   }

   return bRet;
}

//main.cpp

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

int main()
{
    IntArray* a = IntArray::NewInstance(5);

    printf("a.length = %d\n", a->length());

    a->set(0, 1);

    for(int i = 0; i< a->length(); i++)
    {
        int v = 0;

        a->get(i, v);

        printf("a[%d] = %d\n", i, v);
    }

    delete a;

    return 0;
}

4. 小结

(1)构造函数只能决定对象初始化状态

(2)构造函数中初始化操作的失败不影响对象的诞生

(3)初始化不完全的半成品对象是bug的重要来源

(4)二阶构造人为的将初始化过程分为两个部分

(5)二阶构造能够确保创建的对象都是完整初始化的

时间: 2024-09-30 20:08:40

第27课 二阶构造模式的相关文章

第27课二阶构造模式(上)---------出现的背景

构造函数的回顾关于构造函数——类的构造函数用于对象的初始化——构造函数与类同名并且没有返回值——构造函数在对象定义时自动被调用 问题:1. 如何判断构造函数的执行结果?   目前来说,没有办法来判断构造函数的执行结果2. 在构造函数中执行return语句会发生什么?    在构造函数中可以存在return语句,return之后下面的代码就无法执行,会影响对象的初始状态3. 构造函数执行结束是否意味着对象构造成功?   对象的诞生与构造函数的执行结果是没有任何关系的.如果构造函数没有执行成功,只会

C++之二阶构造模式

前言:C++中经常会因为调用系统资源失败导致出现BUG,所以在类调用构造函数需要分配系统资源时会出现BUG,从而导致类对象虽然被创建,但是只是个半成品,为了避免这种情况需要使用二阶构造模式 二阶构造模式 源码如下 1 // 二阶构造.cpp : 定义控制台应用程序的入口点. 2 // 3 4 #include "stdafx.h" 5 #include<iostream> 6 7 using namespace std; 8 9 class test 10 { 11 pri

二阶构造模式

模式:方法.设计模式,就是设计方法.前人证明了的行之有效的方法. 构造函数: 1.关于构造函数 -类的构造函数用于对象的初始化. -构造函数与类同名并且没有返回值. -构造函数在对象定义时自动被调用. 问题: 1.如何判断构造函数的执行结果? 2.在构造函数中执行return语句会发生什么? 3.构造函数执行结束是否意味对象构造成功? 编程实验:异常的构造函数.cpp 1 #include <stdio.h> 2 3 class Test 4 { 5 int mi; 6 int mj; 7 b

C++--二阶构造模式

A.关于构造函数1.类的构造函数用于对象的初始化2.构造函数与类同名并且没有返回值3.构造函数在对象定义时被自动被调用Q.问题的出现1.如何判断构造函数的执行结果?2.在构造函数中执行return语句会发生什么?3.构造函数执行结束是否意味着对象构造成功?代码示例 #include <iostream> using namespace std; class Test { int mi; int mj; public: Test(int i, int j) { mi = i; mj = j }

第27课 应用程序中的主窗口

1. 主窗口的概念 (1)主窗口是与用户进行长时间交互的顶层窗口 (2)程序的绝大多数功能直接由主窗口提供 (3)主窗口通常是应用程序启动后显示的第一个窗口 (4)整个程序由一个主窗口和多个对话框组成 2. Qt中的主窗口 (1)Qt开发平台中直接支持主窗口的概念 (2)QMainWindow是Qt中主窗口的基类 (3)QMainWindow继承于QWidget是一种容器类型的组件 3. QMainWindow中封装的秘密 (1)菜单栏(2)工具栏(3)中心组件(4)停靠组件(5)状态栏 4.

第27章 结构型模式大PK

27.1 代理模式 VS 装饰模式 27.1.1 代理模式 (1)场景:客人找运动员代理要求安排运动员参加比赛 (2)说明:代理人有控制权,可以拒绝客人的要求,也可以答应安排,甚至自己下去跑(因为有些运动员本身就作自己的代理) [编程实验]找代理安排运动员比赛 //创建型模式大PK——代理模式和装饰模式 //实例:找代理安排运动员比赛 #include <iostream> #include <ctime> using namespace std; //抽象运动员 class IR

EBS OAF 开发中的OAQueryBean的三种构造模式

EBS OAF 开发中的OAQueryBean的构造模式 (版权声明,本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处:否则请与本人联系,违者必究) 当你为pageLayout区域添加一个query 区域时,OAF框架生成一个oracle.apps.fnd.framework.webui.beans.layout.OAQueryBean对象,它依赖于它的配置,并通过一个子控件table, advanced table或者HGrid来实现simple search, advanced

C++--第27课 - 动态类型识别

第27课 - 动态类型识别 问题:下面的程序有问题吗? class Parent { public: virtual -Parent() { } }; class Child : public Parent { }; void test(Parent* p) { Child* c = (Child*)p;  //将父类强制转化为子类 } 1. 动态类型 由于基类指针可以直接指向派生类对象,因此可能存在指针所指类型与具体指向的对象类型不同的情况. (p指向的静态类型为Parent)Parent*

4周第2次课 vim 一般模式光标移动、复制、剪切

四周第二次课(11月7日) 5.1 vim介绍 vi这个命令,它是linux中必不可少的一个工具.早期的Unix系统默认的编辑器的. vi与vim有什么区别? vim是vi的升级版.带彩色和代码提示,有利于提高使用人员的效率. 安装: yum install -y vim-enhanced vim的三种模式:一般模式.编辑模式.命令模式 技巧: !$  表示最后一次输入空格之后的参数 vim 有个比较特殊的用法:# vim +n filename 这里的 n 是一个数字,比如 vim +100