C++静态成员和单例模式

发布时间 2023-08-24 19:52:33作者: 翻斗花园牛大爷!

一、静态成员

Ⅰ.什么是静态成员:

被static修饰的成员变量和成员函数就叫静态成员

Ⅱ.普通成员的特点:
  • 成员变量:每个类对象中都有一份属于自己的成员变量,相互之间没有关联、独立的

  • 成员函数:隐藏着一个this指针,接收调用者的地址用于区分调用者

Ⅲ.静态成员的特点:
  • 静态成员变量:
    ①存储在data或bss内存段中,一个类中的所有静态成员变量只有唯一一份,被所有类对象共享
    ②一旦成员变量被声明为静态成员变量后,通过sizeof计算类字节数时,就不统计该变量的字节数
    ③静态成员变量必须在类内加static声明,在类外单独定义、初始化,定义时无需加static
    ④静态成员变量的生命周期不再依赖于某个对象,伴随整个程序的生命周期
    ⑤因为静态成员变量的存在不依赖于任何类对象,所以可以无需实例化类对象,直接访问静态成员变量

     类名::静态成员变量     (无需实例化对象,但是一般成员变量都是私有的)
     对象名.成员变量/静态成员变量
     对象名.成员变量/静态成员变量
    
  • 静态成员函数:
    ①没有隐藏的this指针,所以在静态成员函数中无法直接访问普通成员变量、普通成员函数,但是可以手动传递对象的地址来间接访问,毕竟静态成员函数还是属于类的
    ②但是可以直接访问静态成员变量、静态成员函数
    ③调用方式

     类名::静态成员函数()   (无需实例化对象)
     对象名.成员函数()/静态成员函数()
     对象名.成员函数()/静态成员函数()
    
Ⅳ.静态成员的作用
  1. 静态成员相当于多了一层类作用域的全局变量、全局函数

  2. 静态成员变量适合存储所有类对象的公共属性,从而节约资源(税率、利率等)

  3. 静态成员函数可以当做访问私有的静态成员变量的公开接口,一方面不破坏类的封装性,另一方面可以无需实例化对象也能调用类的静态成员,让类本身具有管理自己成员的能力

常见面试题
  • C和C++中的static的区别?

二、单例模式(考点)

  • 什么是单例模式:
    只能实例化一个类对象

  • 什么场景下使用单例模式:
    进程管理器、日志管理器、网站访问计数器、应用配置程序、线程池、服务器的连接管理器

Ⅰ.实现单例模式的原理:
  1. 禁止在类外随意实例化对象,把构造函数\拷贝构造私有化

  2. 确保类对象只有一份,在类中定义一个静态的类对象成员变量

  3. 提供一个获取静态类对象成员变量的公开的接口,设计一个静态成员函数用于获取那唯一的一个静态类对象

Ⅱ.饿汉模式的单例:(
  • 程序运行开始时就立即实例化单例类对象,不管后期是否用得到都会完成实例化

  • 优点:不可能被多个线程同时运行创建多份(线程安全)

  • 缺点:如果后期使用不到,就浪费时间、资源

Ⅲ.懒汉模式的单例:(
  • 什么时候使用,什么时候才去实例化单例类对象

  • 优点:使用时才会创建,节约时间、资源

  • 缺点:可能会被多个线程同时实例化,有可能会创建出多个单例类对象(线程不安全)

常考笔试题:实现饿汉、懒汉模式的单例,线程安全的懒汉模式的单例
  • 饿汉单例模式

    #include <iostream>
    using namespace std;class Single
    
    {
        static Single obj;
        Single(void)
        {
            cout << "我是构造函数" << endl;
        }
        Single(const Single& that)
        {
            cout << "我是拷贝构造" << endl;
        }
    public:
        static Single& getobj(void)
        {
            return obj;
        }
        void show(void)
        {
            cout << &obj << endl;
        }
    };
    
    Single Single::obj;
    
    int main(int argc,const char* argv[])
    {
        Single& s = Single::getobj();
        s.show();
        Single& s1 = Single::getobj();
        s1.show();
    }
    
  • 懒汉单例模式

    #include <iostream>
    using namespace std;
    
    class Single
    {
        static Single* obj;
        Single(void)
        {
            cout << "我是构造函数" << endl;
        }
        Single(const Single& that)
        {
            cout << "我是拷贝构造" << endl;
        }
    public:
        static Single& getobj(void)
        {
            if(obj == NULL)
            {
                obj = new Single;
            }
            return *obj;
        }
        void show(void)
        {
            cout << &obj << endl;
        }
    };
    
    Single* Single::obj;
    
    int main(int argc,const char* argv[])
    {
        Single& s = Single::getobj();
        s.show();
        Single& s1 = Single::getobj();
        s1.show();
    }
    
  • 线程安全的懒汉单例模式

    #include <iostream>
    #include <pthread.h>
    using namespace std;
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
    class Single
    {
    	static Single* obj;
    	Single(void)
    	{
    		cout << "我是构造函数" << endl;	
    	}
    	Single(const Single& that)
    	{
    		cout << "我是拷贝构造" << endl;	
    	}
    public:
    	static Single& get_obj(void)
    	{
    		if(NULL == obj)
    		{
    			obj = new Single;	
    		}
    		return *obj;	
    	}
    
    	void show(void)
    	{
    		cout << obj << endl;	
    	}
    };
    
    Single* Single::obj;	
    
    void* run(void* arg)
    {
    	pthread_mutex_lock(&mutex);
    	Single& s = Single::get_obj();
    	pthread_mutex_unlock(&mutex);
    }
    
    int main(int argc,const char* argv[])
    {
    	pthread_t tid[20];
    	for(int i=0; i<20; i++)
    	{
    		pthread_create(&tid[i],NULL,run,NULL);	
    	}
    	for(int i=0; i<20; i++)
    	{
    		pthread_join(tid[i],NULL);	
    	}
    }