关闭

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

标签: 对象实例
1174人阅读 评论(0) 收藏 举报
分类:

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

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,且永远不会改变,所以只会实例化一个对象。这个方法更加便捷高效。
但是上面的代码没有考虑类拷贝的问题,大家参照上面的类拷贝问题可以自己把函数加上,然后去试一试,有问题可以留言大家一起解决~

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:83409次
    • 积分:1492
    • 等级:
    • 排名:千里之外
    • 原创:64篇
    • 转载:4篇
    • 译文:0篇
    • 评论:11条
    最新评论