为什么要用二阶构造?
当类的成员比较简单,如只有赋值等简单操作时,普通的构造函数就可以。
然而实际中,以面向对象的思维开发程序时,类往往十分复杂,设计到动态内存申请、文件打开等操作。然而在调用构造函数后,无法得知这些复杂的操作是否顺利完成。假若动态内存未成功申请,然而对象实例在主程序中依然成功创建,这样的对象称为半成品对象。在后续对该对象的操作,往往会引起程序的奔溃。
为了防止出现这样的情况,我们使用二阶构造函数,中心思路为把类的初始化分为两个阶段,第一阶段为构造不会出错的类成员,第二阶段为构造动态内存申请等可能出错的部分,并以bool
形式返回构造成功与否。这两个阶段的连接依靠类的静态成员函数
第一步:
形式上就是传统的构造函数,不同的是这里需要将该构造函数的访问属性设置为private
,在该构造函数中只进行类中普通成员变量的初始化操作,一般的,纯粹的赋值操作不会发生意外(不成功的情况)
第二步:
一般的,类中额外定义一个名为bool construct()
的私有成员方法,该方法中,进行该类的实例化操作时涉及到的系统资源的申请工作,返回值表示申请的成功或失败
。
#include <iostream>
using namespace std;
class A
{
private:
int m;
int n;
int* p;
A() //第一段构造函数,一般的,纯粹的赋值操作不会发生错误
{
m = 1;
n = 2;
}
bool construct() //第二段构造函数,防止文件打开、系统资源的申请失败导致半成品对象
{
bool ret = true;
p = new int(3);
if (!p)
ret = false;
return ret;
}
public:
static A* NewInstance() //必须写为静态函数,以方便用类名调用该函数, 而不用创建对象实例,返回的是指针类型
{
A* ret = new A(); //完成第一段对象实体
if (!(ret && ret->construct()))//ret->construct()完成第二段对象实体,并利用返回值来判断对象是否创建成功
{
delete ret;
ret = NULL;
}
return ret;
}
void showdata()
{
cout << "m = " << m << endl;
cout << "n = " << n << endl;
cout << "*p = " << *p << endl;
}
};
void main()
{
A* p_A = A::NewInstance(); //静态调用,不同动态申请
p_A->showdata();
delete p_A;
}