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

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

问题:
1. 如何判断构造函数的执行结果?
   目前来说,没有办法来判断构造函数的执行结果
2. 在构造函数中执行return语句会发生什么?
    在构造函数中可以存在return语句,return之后下面的代码就无法执行,会影响对象的初始状态
3. 构造函数执行结束是否意味着对象构造成功?
   对象的诞生与构造函数的执行结果是没有任何关系的。如果构造函数没有执行成功,只会影响它的初始状态,并不影响对象的创建。

异常的构造函数

#include <stdio.h>

class Test
{
    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;
}

在构造函数中执行return语句:对象会被创建成功,但是对象的初始状态会发生异常。例如在这里的本意是将对象的成员mj赋值为2,但是得到的结果却是随机值。

下面可以这样做:

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

这种解决方案确实可以,就是强行的让构造函数有一个返回值。并且手工的调用status来得到构造函数的返回值。这个似乎可以解决问题,但是不够优美。

通过上面的实验,可以得到:
构造函数
——只提供自动初始化成员变量的机会
——不能保证初始化逻辑一定成功
——执行return语句后构造函数立即结束。

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

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

办成品对象的危害

还是以之前创建的那个数组类为例,进行分析。

#include "IntArray.h"

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

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

    m_length = len;
}

IntArray::IntArray(const IntArray& obj)
{
    m_length = obj.m_length;

    m_pointer = new int[obj.m_length];

    for(int i=0; i<obj.m_length; i++)
    {
        m_pointer[i] = obj.m_pointer[i];
    }
}

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

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

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

    return ret;
}

bool IntArray::set(int index, int value)
{
    bool ret = (0 <= index) && (index < length());

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

    return ret;
}

IntArray::~IntArray()
{
    delete[]m_pointer;
}
分析下面这段代码:IntArray::IntArray(int len)
{
    m_pointer = new int[len];   //申请堆空间

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

    m_length = len;
}问题:每次申请堆空间时,你能保证每次都申请成功吗?也许1万次了,出现几次不成功。看上去概率很低,但是我们也不能容忍,你可能会这样去做。
IntArray::IntArray(int len)
{
    m_pointer = new int[len];   //申请堆空间
    if(m_pointer)
    {  for(int i=0; i<len; i++)
      {
          m_pointer[i] = 0;
      }
    }
    m_length = len;
}这样当申请失败了,就不需要执行花括号里面的代码了。看似没有什么问题,也合情合理。注意:前面已经说过,构造函数内执行是否成功,与对象是否创建没有什么关系。上面这个例子中构造函数体内没有执行成功,肯定会影响对象的初始状态,但是用户并不知道这个对象的成员有异常。当用户拿到这个类时,它并不知道你花括号里面的内容没有执行,该怎么用就怎么用。看下面的使用:int main(){  IntArray a(5);      a.set(0,1);}编译没有问题,运行时悲剧就产生了。段错误。出现的原因就是在构造函数中,m_pointer没有申请成功,但是下面又使用了它。





原文地址:https://www.cnblogs.com/-glb/p/11875853.html

时间: 2024-10-07 00:32:43

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

第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,会导

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.

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*

设计模式大类--行为模式(上)

大概有10中行为模式,分为上中下三篇.一.Template(模板)描述:定义一些操作算法的骨架,将其实现延迟到其子类好处:扩展性强 例子:Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: public abstract class Benchmark{ /** * 下面操作是我们希望在子类中完成 */ public abstract void benchmark(); /** * 重复执行benchmark次数 */ public fina

设计模式大类--结构模式(上)

大概有7中结构模式,分为上下两篇.一.Adapter(适配器)描述:将两个不兼容的类结合一起使用,一般需要用到其中某个类的若干方法好处:在两个类直接创建一个混合接口,而不必修改类里面的其他代码 例子:假设我们要打桩,有两种类:方形桩 圆形桩.public class SquarePeg{ public void insert(String str){ System.out.println("SquarePeg insert():"+str); } } public class Roun