zoukankan      html  css  js  c++  java
  • 【面试题002】java实现的单例模式,c++实现单例模式,实现禁止拷贝

    【面试题002】java实现的单例模式,c++实现单例模式,实现禁止拷贝 

    一 c++实现单例模式

    保证一个类,在一个程序当中只有一个对象,只有一个实例,这个对象要禁止拷贝,注意这里要区别于java。否者的话一个程序当中就可能出现多个对象的拷贝。

    我们要禁止拷贝,需要将拷贝构造函数以及等号运算符 声明为私有的,并且呢不提供他们的实现。这样子如果我们代码里面有拷贝构造的话,编译时候会出错。

    仅仅这样子是不够的,我们必须将构造函数声明为私有的,这是为了防止外部呢,任意的构造对象。

    既然我们将构造函数私有化了,外部就不能通过 Singleton s1; 来定义这样一个对象。那我们就需要提供一个接口让外部呢得到这样一个对象。

    Singleton.cpp:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    #include <iostream>
    #include <memory>
    using namespace std;

    class Singleton
    {
    public:
        /*这个GetInstance是静态的由类直接调用的*/
        static Singleton *GetInstance()
        {

            /*用这种方法会出现构造出来的这个对象什么时候释放的问题*/
            /*      if (instacne_ == NULL)
                    {
                        instacne_ = new Singleton;
                    }
                    return instacne_;*/


            /* 把裸指针用智能指针来管理
             * 智能指针是重载了点号运算符的,我们访问类本身的get()方法,获得裸指针
             */

            if (!instacne_.get())
            {
                instacne_ = auto_ptr<Singleton>(new Singleton);
            }

            return instacne_.get();
        }

        ~Singleton()
        {
            cout << "~Singleton ..." << endl;
        }
    private:
        // 禁止拷贝--构造函数和等号运算符声明为私有的,并且不提供实现。
        Singleton(const Singleton &other);
        Singleton &operator=(const Singleton &other);

        // 将构造函数说明为私有的
        Singleton()
        {
            cout << "Singleton ..." << endl;
        }
        /*这实际上是一个静态的类对象,这里仅仅是引用性说明,她的定义应该在类的外边*/
        static auto_ptr<Singleton> instacne_;
    };

    /*定义性说明*/
    auto_ptr<Singleton> Singleton::instacne_;
     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    int main(void)
    {
        //Singleton s1;
        //Singleton s2;

        Singleton *s1 = Singleton::GetInstance();
        Singleton *s2 = Singleton::GetInstance();

        //Singleton s3(*s1);        // 调用拷贝构造函数

        return 0;
    }

     

    Makefile:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    .PHONY:clean  
    CPP=g++  
    CFLAGS=-Wall -g  
    BIN=test  
    OBJS=Singleton.o  
    LIBS=  
    $(BIN):$(OBJS)  
        $(CPP) $(CFLAGS) $^ -o $@ $(LIBS)  
    %.o:%.cpp  
        $(CPP) $(CFLAGS) -c $< -o $@  
    clean:  
        rm -f *.o $(BIN)  

    运行结果

    Singleton ...
    ~Singleton ...

    裸指针呢,用智能指针来管理静态的一个类对象,当整个程序结束的时候,静态对象也就被销毁了,

    那么静态对象的销毁就会导致这个类对象的析构函数被调用,

    instance_.get()
    这个get()方法是 智能指针提供的是吧
    auto_ptr中有个get方法
    还有你给的析构函数  里面并没有释放 那个指针所指的资源 
    是程序结束的时候,由智能指针来释放的
    智能指针变量 本身不是堆区内存,
    智能指针对象销毁的时候,智能指针对象的析构函数会去销毁它所包裹的堆对象

    只不过说 智能指针释放了,静态的变量的时候会调用这个变量的析构函数
    析构函数是,delete的时候调用的,这个delete操作是在智能指针对象的析构函数中调用的,从而引发了堆对象的析构

    如果正常调用析构函数的情况,析构函数你是需要自己是释放对象的资源的,(因为是堆对象,堆上的东西自己释放)
    1. //Singleton s1;  
    2. //Singleton s2;  
    3.   
    4. //Singleton s3(*s1);        // 调用拷贝构造函数  

    这些情况下都是错误的,

    运行结果:

    g++ -Wall -g -c Singleton.cpp -o Singleton.o
    Singleton.cpp: 在函数‘int main()’中:
    Singleton.cpp:36:2: 错误: ‘Singleton::Singleton(const Singleton&)’是私有的
    Singleton.cpp:59:18: 错误: 在此上下文中
    Singleton.cpp:57:13: 警告: 未使用的变量‘s2’ [-Wunused-variable]
    make: *** [Singleton.o] 错误 1

    二,实现禁止拷贝

    Nocopyable这个类如何保证禁止拷贝,她的实现和Singleton类的实现差不多。

    Noncopyable.cpp:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    #include <iostream>
    #include <memory>
    using namespace std;

    class Noncopyable
    {
    protected:
        Noncopyable() {}
        ~Noncopyable() {}
    private:
        Noncopyable(const Noncopyable &);
        const Noncopyable &operator=(const Noncopyable &);
    };


    class Parent : private Noncopyable
    {
    public:
        Parent()
        {

        }
        Parent(const Parent &other) : Noncopyable(other)
        {

        }
    };

    class Child : public Parent
    {
    public:
        //Child(const Child& other)
        //{

        //}
    };

    int main()
    {
        /*这两种情况都是失败的*/
        //Parent p1;
        //Parent p2(p1);
        // 要调用Parent拷贝构造函数,
        //Parent构造函数又调用Noncopyable的拷贝构造函数

        Child c1;
        Child c2(c1);
        return 0;
    }

    注意:

    private 是实现继承,并不是为了继承她的接口

    public 是接口继承

    Makefile:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    .PHONY:clean  
    CPP=g++  
    CFLAGS=-Wall -g  
    BIN=test  
    OBJS=Noncopyable.o  
    LIBS=  
    $(BIN):$(OBJS)  
        $(CPP) $(CFLAGS) $^ -o $@ $(LIBS)  
    %.o:%.cpp  
        $(CPP) $(CFLAGS) -c $< -o $@  
    clean:  
        rm -f *.o $(BIN)  
    运行结果:
     
    1
    2
    3
    4
    5
     
    g++ -Wall -g -c Noncopyable.cpp -o Noncopyable.o
    Noncopyable.cpp: 在复制构造函数‘Parent::Parent(const Parent&)’:
    Noncopyable.cpp:11:2: 错误: ‘Noncopyable::Noncopyable(const Noncopyable&)’是私有的
    Noncopyable.cpp:23:49: 错误: 在此上下文中
    make: *** [Noncopyable.o] 错误 1

    这里我们需要注意的地方是,

    对于构造函数来说,如果基类有默认构造函数,即使我们没有写 :Noncopyable()这句话,他也是会自动调用基类的默认构造函数的,

    但是拷贝构造函数就不一样啦,如果我们没有写 :Noncopyable(other)这句话,是不会调用基类的拷贝构造函数的,

    当然如果基类没有默认的构造函数,那么这个时候呢,一定要在成员列表中给出对基类构造函数的调用。

     

    JAVA实现的单例模式:

    读取配置文件,并且实例化了一个对象,这个对象保证只有一个。

     Java Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     

    package com.ebupt.ebms.conf;

    /**
     * @author zling Create on 2011-3-7
     * @version 1.0
     */

    public class MainConfig
    {
        private String logPath = ""// 上传的各种日志的本地路径

        private static MainConfig instance = new MainConfig();//懒人模式

        public static MainConfig getInstance()
        {
            if (instance == null)
                instance = new MainConfig();
            return instance;
        }

        public String string()
        {

            StringBuffer sb = new StringBuffer();
            sb.append("logPath : ").append(logPath).append(" ");
            return sb.toString();
        }

        public String getLogPath()
        {
            return logPath;
        }

        public void setLogPath(String logPath)
        {
            this.logPath = logPath;
        }

    }
  • 相关阅读:
    第一个WCF的程序
    第一节 SOA的基本概念和设计思想
    数组拷贝 copyOf()
    dict和set
    类的构造函数
    深入理解 Python 异步编程(上)
    Nifi自定义processor
    java inputstream to string stack overflow
    java inputstream to string
    oracle 导入 dmp
  • 原文地址:https://www.cnblogs.com/codemylife/p/3657302.html
Copyright © 2011-2022 走看看