c++类的二阶构造函数主要适用于在构造函数申请系统资源的场景。普通构造函数的作用是初始化对象,若在初始化过程中不能按照程序员预期的进行,那么将会得到一个半成品对象。以下面代码为例:
using namespace std;
class SecondOrder
{
private:
char* pchar;
int val;
public:
SecondOrder()
{
pchar = new char;
val = 5;
}
~SecondOrder()
{
delete pchar;
pchar = NULL;
}
void SetValue(char c, int i)
{
*pchar = c;
val = i;
}
void PrintValue(void)
{
cout << "*pchar = " << *pchar << endl;
cout << "val = " << val << endl;
}
};
int main(void)
{
SecondOrder s;
s.SetValue('6', 9);
s.PrintValue();
return 0;
}
编译运行:
构造函数中执行动态分配,这就意味着存在分配异常的可能性,即pchar指针可能为NULL。那么:
(1) 构造函数无返回值,类的定义者无法知道构造函数是否执行成功。要表示这种错误,只能通过类中某个状态量表示
(2) 若判断动态分配失败后直接return,还会导致val未被初始化,所以形成半成品对象,对半成品对象的任务操作都可能引发段错误
这时候可以采用二阶构造的方法:
二阶构造即将类的构造过程分为与资源无关的初始化操作和需要使用系统资源的操作,前者不可能出现异常现象,后者则可能会申请内存失败、文件打开失败等异常。
using namespace std;
class SecondOrder
{
private:
char* pchar;
int val;
SecondOrder() //实现第一阶段的构造
{
val = 5;
}
bool construct() //实现第二阶段的构造
{
pchar = new char;
if (NULL == pchar)
return false;
return true;
}
public:
static SecondOrder* instance() //类的使用者要调用的接口,用于返回对象的指针
{
SecondOrder* ret = new SecondOrder();
if (!(ret && ret->construct())) //两个new操作只要任务失败,ret都将为NULL
{
delete ret;
ret = NULL;
}
return ret;
}
~SecondOrder()
{
delete pchar;
pchar = NULL;
}
void SetValue(char c, int i)
{
*pchar = c;
val = i;
}
void PrintValue(void)
{
cout << "*pchar = " << *pchar << endl;
cout << "val = " << val << endl;
}
};
int main(void)
{
SecondOrder *ps = SecondOrder::instance();
if (ps != NULL)
{
ps->SetValue('6', 9);
ps->PrintValue();
}
else
cout << "ps = NULL" << endl;
return 0;
}
用二阶构造的方式设置类的构造函数,就不能让用户利用该类直接生成对象,因为这样操作会使得默认为构造函数被调而忽略了二阶构造的construct()函数。用户要生成对象需要使用类中的静态函数instance(),instance()执行new对象操作,此时会调用默认构造函数,在此函数中实现不可能会出现异常的操作,称为一阶构造。new成功的前提下调用construct()函数,在此函数中实现可能会出现异常的操作,称为二阶构造。在确保一阶构造和二阶构造都执行成功的前提下返,instance才返回new的对象的地址,反之返回NULL。