您的位置:首页 > 其它

设计模式之单例类——如何让一个类只实例化一个对象

2016-03-31 22:17 351 查看
其实这是一道面试题。

这道题的思路是,我只让这个类通过一个公有函数实例化对象,即可以将构造函数设置为私有成员函数。

include <iostream>
using namespace std;

class Single
{
public:

static Single& SingleCreate()
{
if (m == NULL)
{
m = new Single();
}
return *m;
}
~Single()
{
delete m;
}

Single(const Single &a)
{
if (m == NULL)
{
m = new Single();
}
}

private:
Single()
{}
static  Single *m;
};

Single* Single::m = NULL;

int main()
{
Single a = Single::SingleCreate();
}


这是我第一次写出的代码,我本来认为这样就可以了,结果经过我的调试,发现这样写是有问题的。



通过上面的图片可以看出,我们实例化的a的地址,跟在SingleCreate函数中返回的m的值是不同的,即这个类实例化了两个对象,这样就偏题了。

经过分析,我们现在来看SingleCreate函数

static Single& SingleCreate()
{
if (m == NULL)
{
m = new Single();
}
return *m;
}


这里retuen 的*m,会自动生成拷贝构造函数,因为return *m是返回一个对象,这里是返回临时变量,自动调用拷贝构造函数,因为我们没有定义拷贝构造函数,所以这里会自动生成一个拷贝构造函数。

所以达不到只实例化一个对象的目的

经过上面的分析,经代码优化为

class Single
{
public:

static Single* SingleCreatePtr()
{
if (m == NULL)
{
m = new Single();
}
return m;
}
~Single()
{
delete m;
}

private:
Single()
{}

static  Single *m;
};
Single* Single::m = NULL;
int main()
{
Single *a = Single::SingleCreatePtr();
}


这个时候经过调试,得到下面



这个时候就得到的是一个对象。因为传指针的实质是在传地址,不会产生临时变量。

现在已经解决了在返回值时只实例化一个对象的问题

接下来看第三个问题

三、构造函数

接下来我们在main函数中加这么一句话:

Single *b = a;


这个时候会发生什么呢?

对,会实例化出另一个对象,这是因为编译器自动生成了赋值构造函数,就像上面的拷贝构造函数一样,都是编译器自动生成并调用的,那么如何防止这些情况的发生?

我的方法是在类中只声明不定义拷贝构造函数以及赋值构造函数。



class Single
{
public:

static Single& SingleCreate()
{
if (m == NULL)
{
m = new Single();
}
return *m;
}
static Single* SingleCreatePtr()
{
if (m == NULL)
{
m = new Single();
}
return m;
}
~Single()
{
delete m;
}

private:
Single()
{}
Single(const Single &a);
Single& operator = (const Single &a);
static  Single *m;
};


即将拷贝构造函数和赋值运算符重载函数都变成私有的成员函数,在外不可调用,就避免了因为构造函数多实例化对象的情况。

四、通过静态局部变量

class Single
{
private:
Single()   //构造函数是私有的
{
}
public:
static Single & GetInstance()
{
static Single instance;   //局部静态变量
return instance;
}
};


静态局部变量在GetInstance函数中被定义,初始化为0,且静态局部变量存放在内存的全局数据区。函数结束时,静态局部变量不会消失,每次该函数调用 时,也不会为其重新分配空间。它始终驻留在全局数据区,直到程序运行结束。静态局部变量的初始化与全局变量类似.如果不为其显式初始化,则C++自动为其 初始化为0。

静态局部变量与全局变量共享全局数据区,但静态局部变量只在定义它的函数中可见。

通过声明静态局部变量,但不进行初始化及赋值,那么编译器自动初始化为0,且永远不会改变,所以只会实例化一个对象。这个方法更加便捷高效。

但是上面的代码没有考虑类拷贝的问题,大家参照上面的类拷贝问题可以自己把函数加上,然后去试一试,有问题可以留言大家一起解决~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: