【C++修炼之路】33.特殊类设计

这篇具有很好参考价值的文章主要介绍了【C++修炼之路】33.特殊类设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式
每一个不曾起舞的日子都是对生命的辜负

  • 掌握常见特殊类的设计方式

一.设计一个类,不能被拷贝

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

  • C++98

    将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。

class CopyBan
{
  // ...
 
private:
  CopyBan(const CopyBan&);
  CopyBan& operator=(const CopyBan&);
  //...
};

原因:

  1. 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了
  2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。
  • C++11

    C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。

class CopyBan
{
  // ...
  CopyBan(const CopyBan&)=delete;
  CopyBan& operator=(const CopyBan&)=delete;
  //...
};

二.设计一个类,只能在堆上创建对象

1. 普通类的创建对象

普通的类,可以在三种位置上创建对象:

  1. 静态区
#include<iostream>
using namespace std;
class HeapOnly
{};
int main()
{
	HeapOnly hp1;//栈
	HeapOnly* php2 = new HeapOnly;//堆
	static HeapOnly hp3;//静态区
	return 0;
}

2.只能在堆上创建对象的类

要想只能在堆上创建对象,那一定需要在构造函数上动手脚,因为构造函数默认在栈上创建对象。

实现方式:

  1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
  2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。
#include<iostream>
using namespace std;
class HeapOnly
{
public:
	static HeapOnly* CreateObject()
	{
		return new HeapOnly;
	}
private:
	HeapOnly()
    {}
};

int main()
{
	HeapOnly* php = HeapOnly::CreateObject();
	return 0;
}

为什么要加上static?

如果CreateObject不加上static,那么在调用该方法就需要在存在对象的基础上才能使用该方法,而该对象默认一定会用构造函数,但是构造函数已经私有化,这就是一个先有鸡还是先有蛋的问题,因此一定要加上static。

但是就目前的情况,仍然可能在栈上开辟对象,首先友元一定是可以的。其次,拷贝构造函数没有显示化调用会默认生成,因此,如下方式仍可以在栈上创建对象:

int main()
{
	HeapOnly* php2 = HeapOnly::CreateObject();
	HeapOnly php3(*php2);//栈上创建对象
	return 0;
}

所以,拷贝构造函数同样需要禁掉,才是只能在堆上创建的类:

#include<iostream>
using namespace std;
class HeapOnly
{
public:
	static HeapOnly* CreateObject()
	{
		return new HeapOnly;
	}
private:
	HeapOnly() {}
	HeapOnly(const HeapOnly&) = delete;
};

int main()
{
	HeapOnly* php2 = HeapOnly::CreateObject();
	return 0;
}

只在堆上创建类的第二种方式:析构私有化

如果析构私有化,那么直接创建对象会显示没有合适的构造函数,从而无法在栈上创建对象。

class HeapOnly
{
public:
	HeapOnly()
	{}
private:
	~HeapOnly()
	{}

	HeapOnly(const HeapOnly&) = delete;
};

int main()
{
	HeapOnly hp1;
	return 0;
}

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式

但此时可以在堆上创建,那么此时分为如下步骤:

  1. 析构函数私有化
  2. 构造函数public显示调用
  3. 新增Destory方法,用来释放堆空间
class HeapOnly
{
public:
	HeapOnly()
	{}
	void Destory()
	{
		this->~HeapOnly();
	}
private:
	~HeapOnly()
	{}

	HeapOnly(const HeapOnly&) = delete;
};

int main()
{
	HeapOnly* php1 = new HeapOnly;
	php1->Destory();

	return 0;
}

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式

Destory对于static没有要求,用不用static修饰完全是我们自己所决定的。

注:在vs2019中,上面的this必须显示调用才没有错误。

三.设计一个类,只能在栈上创建对象

方法一:(同上)

  1. 将构造函数私有化。
  2. 然后设计静态方法创建对象返回即可。
//请设计一个类,只能在栈上创建对象
class StackOnly
{
public:
	static StackOnly CreateObj()
	{
		return StackOnly();
	}
private:
	StackOnly()
	{}

};
int main()
{
	StackOnly so1 = StackOnly::CreateObj();
	// 下面两种静态区和堆的位置都不能创建
	//static StackOnly so2;
	//StackOnly* pso3 = new StackOnly;
	return 0;
}

实际上,这种方法也没有彻底的封死,下面这种方式仍然可以在静态区创建:

int main()
{
	static StackOnly so2 = StackOnly::CreateObj();
	return 0;
}

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式

解决这个问题的方式:

这里设计到的强制类型转换,强制类型转换中间会生成一个临时对象,将这个临时对象拷贝给需要定义的对象,若把拷贝构造封住,那么不仅这个会报错,前面的也会报错,因为前者的赋值也是将返回的对象临时拷贝:

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式

因此,没有什么很好的办法去完全的封死。但硬要封死,即把拷贝构造封住,那就不要用 = 获取,而是直接调用,如下:

//请设计一个类,只能在栈上创建对象
class StackOnly
{
public:
	static StackOnly&& CreateObj()
	{
		return StackOnly();
	}

	void Print() const
	{
		cout << "StackOnly::Print()" << endl;
	}
private:
	StackOnly()
	{}
	StackOnly(const StackOnly&) = delete;

};
int main()
{
	/*StackOnly so1 = StackOnly::CreateObj();
	static StackOnly so2 = StackOnly::CreateObj();*/

	StackOnly::CreateObj().Print();
	const StackOnly& so4 = StackOnly::CreateObj();
	so4.Print();
	return 0;
}

目的就是防止拷贝。

ps,由于StackOnly()是局部对象,出了作用域被销毁,因此采用右值引用才可以传出。


方法二:封注operator newoperator delete

class StackOnly
{
public:
    StackOnly()
	{}
	static StackOnly CreateObj()
	{
		return StackOnly();
	}
	void* operator new(size_t size) = delete;
	void operator delete(void* p) = delete;
	
};

这种方式同样可以,因为在new对象的过程中,一定会存在operator new的步骤。但是这种方法只能封住堆上的,却无法封住静态的。

所以最好的方式就是用方式一。

四.设计一个类,不能被继承

  • C++98方式
// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:
    static NonInherit GetInstance()
    {
        return NonInherit();
    }
private:
    NonInherit()
    {}
};
  • C++11方法

final关键字,final修饰类,表示该类不能被继承。

class A  final
{
  // ....
};

五.单例模式

  • 单例模式:只能创建一个对象。

1.什么是设计模式?

设计模式是在软件工程中经过反复实践证明的一套解决问题的经验总结,用于解决常见的设计问题。以下是一些常见的设计模式:

  1. 创建型模式(Creational Patterns):

    • 工厂方法模式(Factory Method Pattern)
    • 抽象工厂模式(Abstract Factory Pattern)
    • 单例模式(Singleton Pattern)
    • 建造者模式(Builder Pattern)
    • 原型模式(Prototype Pattern)
  2. 结构型模式(Structural Patterns):

    • 适配器模式(Adapter Pattern)
    • 桥接模式(Bridge Pattern)
    • 组合模式(Composite Pattern)
    • 装饰者模式(Decorator Pattern)
    • 外观模式(Facade Pattern)
    • 享元模式(Flyweight Pattern)
    • 代理模式(Proxy Pattern)
  3. 行为型模式(Behavioral Patterns):

    • 观察者模式(Observer Pattern)
    • 状态模式(State Pattern)
    • 策略模式(Strategy Pattern)
    • 命令模式(Command Pattern)
    • 职责链模式(Chain of Responsibility Pattern)
    • 迭代器模式(Iterator Pattern)
    • 中介者模式(Mediator Pattern)
    • 备忘录模式(Memento Pattern)
    • 访问者模式(Visitor Pattern)
    • 模板方法模式(Template Method Pattern)
  4. 并发型模式(Concurrent Patterns):

    • 信号量模式(Semaphore Pattern)
    • 线程池模式(Thread Pool Pattern)
    • 读写锁模式(Read-Write Lock Pattern)
    • 生产者消费者模式(Producer-Consumer Pattern)

以上仅是一些常见的设计模式,实际上还有其他的设计模式。每个设计模式都有特定的应用场景和解决问题的方式。请注意,在使用设计模式时,应根据具体的需求和情况来选择适当的设计模式。

比如迭代器模式,把复杂的东西给封装好,使用时就可以避免接触复杂的底层结构。

比如配接器模式等等,也是这个意思。

使用设计模式的目的: 为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

2.单例模式

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。

由于全局对象只能有一个,换句话说是获取这个对象,那就需要对构造函数进行操作。

单例模式有两种实现模式:饿汉模式、懒汉模式

饿汉模式:不管你将来用不用,程序启动时就创建一个唯一的实例对象。

饿汉模式的条件:main函数之前就初始化

设计饿汉模式的步骤:

  1. 将构造函数设成private,以及封死拷贝构造和重载赋值
  2. 定义成员变量,变量类型为static 类型名
  3. 在类外初始化这个单例的对象
  4. 添加其它成员方法
//单例模式的类:全局只有一个唯一对象
// 饿汉模式(main函数之前初始化)
// 缺点:1、单例对象初始化时对象太多,导致启动慢 
//		 2、多个单例类有初始化依赖关系,饿汉模式无法控制
class InfoSingleton
{
public:
	static InfoSingleton& GetInstance()
	{
		return _sins;
	}

	void Insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void Print()
	{
		for (auto kv : _info)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}
private:
	InfoSingleton()
	{}
	InfoSingleton(const InfoSingleton&) = delete;
	InfoSingleton& operator=(const InfoSingleton& info) = delete;
	map<string, int> _info;
	// ...
private:
	static InfoSingleton _sins;
};

InfoSingleton InfoSingleton::_sins;

int main()
{
	InfoSingleton::GetInstance().Insert("张三", 10000);
	InfoSingleton& infosl = InfoSingleton::GetInstance();
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);

	infosl.Print();
	cout << endl;
	InfoSingleton::GetInstance().Insert("张三", 18000);
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);
	infosl.Print();
	return 0;
}

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式

可见在调用时可以通过引用来简化代码量。

饿汉模式的缺点:

  1. 单例对象初始化数据太多,导致启动慢
  2. 多个单例类有初始化依赖关系,饿汉模式无法控制

假设有两个单例类A和B,分别代表数据库和文件系统,要求先初始化A,再初始化B,并且B会依赖A,那么此时饿汉模式就无法控制顺序。

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。

懒汉模式

如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。

懒汉模式的条件:

  1. 对象在main函数之后才会创建,不会影响启动顺序
  2. 可以主动控制创建顺序

设计懒汉模式的步骤:(与饿汉模式基本相同)

  1. 将构造函数设成private,以及封死拷贝构造和重载赋值
  2. 定义成员变量,变量类型为static 类型名
  3. 在类外初始化这个单例的对象
  4. 添加其它成员方法

与饿汉模式的区别:

  1. 对象在main函数之后才会创建,不会影响启动顺序
  2. 可以主动控制创建顺序
  3. 将对象的创建改为在堆上创建
  4. 懒汉模式存在多个对象一起调用GetInstance的情况,存在线程安全的风险,可能new出来多个对象,因此需要加锁,需要新增一个锁的成员对象,并定义为static类型;饿汉模式一开始就一个对象,不用创建,所以不用锁。

注意:锁不能被拷贝,因此定义锁的成员变量时可以用指针(地址)或者引用的方式定义,C++采用地址的行为不常见,用引用更好。

加锁也是有讲究的,如果像这样的代码:

//多个对象一起调用GetInstance,存在线程安全的风险,可能new出来多个对象,因此需要加锁
static InfoSingleton& GetInstance()
{
    _pmtx.lock();
    if (_psins == nullptr)//避免对象new出来以后每次都加锁,提高性能
    {
        _psins = new InfoSingleton;
    }
    _pmtx.unlock();
    return *_psins;
}

由于这种方式每次都需要加锁,但实际上只有第一次创建对象才需要加锁,所以为了避免锁影响效率,使用双层if检查;此外,对于new,一旦抛异常,就需要捕获,此时可以使用try-catch,但这种写法不可行,通过之前智能指针的RAII思想,我们可以自己设定一个类:基于RAII思想的管理类,来防止锁的问题。

为什么try-catch不可行,因为还在加锁阶段,一旦进行捕获跳转,那么这把锁会一直锁住,为了避免出现这种情况,才使用RAII的思想。C++线程库中也有对应的库函数方法,但是这里仍然可以手撕一个。

//RAII的锁管理类
template<class Lock>
class LockGuard
{
public:
	LockGuard(Lock& lk)
		:_lk(lk)
	{
		lk.lock();
	}

	~LockGuard()
	{
		_lk.unlock();
	}
private:
	Lock& _lk;//成员变量用引用-->避免拷贝
};

//懒汉模式
//1、对象在main函数之后才会创建,不会影响启动顺序
//2、可以主动控制创建顺序

//问题:
class InfoSingleton
{
public:
	//多个对象一起调用GetInstance,存在线程安全的风险,可能new出来多个对象,因此需要加锁
	static InfoSingleton& GetInstance()
	{
		//第一次获取单例对象的时候创建对象
		//双检查加锁
		if (_psins == nullptr)//避免对象new出来以后每次都加锁,提高性能
		{
			// t1  t2
			LockGuard<mutex> mtx(_smtx);
			if (_psins == nullptr) //保证线程安全且只new一次
			{
				_psins = new InfoSingleton;
			}
		}

		return *_psins;
	}

	void Insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void Print()
	{
		for (auto kv : _info)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}
private:
	InfoSingleton()
	{}
	InfoSingleton(const InfoSingleton&) = delete;
	InfoSingleton& operator=(const InfoSingleton& info) = delete;
	map<string, int> _info;
	// ...
private:
	static InfoSingleton* _psins;
	static mutex _smtx;
};

InfoSingleton* InfoSingleton::_psins = nullptr;
mutex InfoSingleton::_smtx;

int main()
{
	InfoSingleton::GetInstance().Insert("张三", 10000);
	InfoSingleton& infosl = InfoSingleton::GetInstance();
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);

	infosl.Print();
	cout << endl;
	InfoSingleton::GetInstance().Insert("张三", 18000);
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);
	infosl.Print();
	return 0;
}

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式

库中也有对应的加锁方法:

static InfoSingleton& GetInstance()
{
    //第一次获取单例对象的时候创建对象
    //双检查加锁
    if (_psins == nullptr)//避免对象new出来以后每次都加锁,提高性能
    {
        // t1  t2
        //LockGuard<mutex> mtx(_smtx);
        std::lock_guard<mutex> lock(_smtx);//库中的方法
        if (_psins == nullptr) //保证线程安全且只new一次
        {
            _psins = new InfoSingleton;
        }
    }

    return *_psins;
}

new出来之后是否需要释放?

一般单例模式对象不需要考虑释放。单例模式的类的一个对象通常在整个程序运行期间都会使用,因此最后不delete也不会有问题,只要进程最终正常结束,对象的资源就会由OS自动释放。

什么时候单例模式的对象需要释放?

单例对象不用时,必须手动处理,一些资源需要保存。假设工资名单需要保存到文件里,要求系统结束之前将信息保存进去,此时就需要手动处理。所以,可以新增一个方法DelInstance(),是否需要调用取决于自己:

//懒汉模式
//1、对象在main函数之后才会创建,不会影响启动顺序
//2、可以主动控制创建顺序
class InfoSingleton
{
public:
	//多个对象一起调用GetInstance,存在线程安全的风险,可能new出来多个对象,因此需要加锁
	static InfoSingleton& GetInstance()
	{
		//第一次获取单例对象的时候创建对象
		//双检查加锁
		if (_psins == nullptr)//避免对象new出来以后每次都加锁,提高性能
		{
			// t1  t2
			//LockGuard<mutex> mtx(_smtx);
			std::lock_guard<mutex> lock(_smtx);
			if (_psins == nullptr) //保证线程安全且只new一次
			{
				_psins = new InfoSingleton;
			}
		}

		return *_psins;
	}

	//一般单例对象不需要考虑释放
	//单例对象不用时,必须手动处理,一些资源需要保存
	static void DelInstance()
	{
		//保存数据到文件
		// ...
		std::lock_guard<mutex> lock(_smtx);
		if (_psins)
		{
			delete _psins;
			_psins = nullptr;
		}
	}

	void Insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void Print()
	{
		for (auto kv : _info)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}
private:
	InfoSingleton()
	{}
	InfoSingleton(const InfoSingleton&) = delete;
	InfoSingleton& operator=(const InfoSingleton& info) = delete;
	map<string, int> _info;
	// ...
private:
	static InfoSingleton* _psins;
	static mutex _smtx;
};

InfoSingleton* InfoSingleton::_psins = nullptr;
mutex InfoSingleton::_smtx;

int main()
{
	InfoSingleton::GetInstance().Insert("张三", 10000);
	InfoSingleton& infosl = InfoSingleton::GetInstance();
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);

	infosl.Print();
	cout << endl;
	InfoSingleton::GetInstance().Insert("张三", 18000);
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);
	infosl.Print();

	InfoSingleton::DelInstance();//主动调用
	return 0;
}

如果忘记主动调用,同样会产生错误,因此仍需要设计一个能够自动回收的方式,这里采用新增一个内部类GC,利用RAII的思想,一旦忘主动回收,其在main函数结束时就会自动回收,此时就需要新增一个成员变量以及内部类:

注:内部类是外部类的友元

//懒汉模式
//1、对象在main函数之后才会创建,不会影响启动顺序
//2、可以主动控制创建顺序
class InfoSingleton
{
public:
	//多个对象一起调用GetInstance,存在线程安全的风险,可能new出来多个对象,因此需要加锁
	static InfoSingleton& GetInstance()
	{
		//第一次获取单例对象的时候创建对象
		//双检查加锁
		if (_psins == nullptr)//避免对象new出来以后每次都加锁,提高性能
		{
			// t1  t2
			//LockGuard<mutex> mtx(_smtx);
			std::lock_guard<mutex> lock(_smtx);
			if (_psins == nullptr) //保证线程安全且只new一次
			{
				_psins = new InfoSingleton;
			}
		}

		return *_psins;
	}

	//一般单例对象不需要考虑释放
	//单例对象不用时,必须手动处理,一些资源需要保存
	static void DelInstance()
	{
		//保存数据到文件
		// ...
		std::lock_guard<mutex> lock(_smtx);
		if (_psins)
		{
			delete _psins;
			_psins = nullptr;
		}
	}
	//忘记调用DelInstance(),自动回收
	class GC
	{
	public:
		~GC()
		{
			if (_psins)
			{
				cout << " ~GC()" << endl;
				DelInstance();
			}
		}
	};

	void Insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void Print()
	{
		for (auto kv : _info)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}
private:
	InfoSingleton()
	{}
	InfoSingleton(const InfoSingleton&) = delete;
	InfoSingleton& operator=(const InfoSingleton& info) = delete;
	map<string, int> _info;
	// ...
private:
	static InfoSingleton* _psins;
	static mutex _smtx;
	static GC _gc;
};

InfoSingleton* InfoSingleton::_psins = nullptr;
mutex InfoSingleton::_smtx;
InfoSingleton::GC InfoSingleton::_gc;

int main()
{
	InfoSingleton::GetInstance().Insert("张三", 10000);
	InfoSingleton& infosl = InfoSingleton::GetInstance();
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);

	infosl.Print();
	cout << endl;
	InfoSingleton::GetInstance().Insert("张三", 18000);
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);
	infosl.Print();
	return 0;
}

【C++修炼之路】33.特殊类设计,C++,c++,设计模式,单例模式

因此,可以主动回收,也可以在程序结束时自动回收,但单例对象一般不需要回收。

实现懒汉的另一种方式:

懒汉模式的实现还有另一种方式,直接static,也是只创建一次对象,所以下面的方式也可以,但不是一种通用的方式。文章来源地址https://www.toymoban.com/news/detail-538798.html

//是懒汉:因为静态的局部变量是在main函数之后才创建初始化的:局部静态变量的初始化只初始化一次。
//C++11之前,不能保证sinst的初始化是线程安全的。
//C++11之后,可以。
class InfoSingleton
{
public:
	//多个对象一起调用GetInstance,存在线程安全的风险,可能new出来多个对象,因此需要加锁
	static InfoSingleton& GetInstance()
	{
		static InfoSingleton sinst;
		return sinst;
	}


	void Insert(string name, int salary)
	{
		_info[name] = salary;
	}

	void Print()
	{
		for (auto kv : _info)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}
private:
	InfoSingleton()
	{
		cout << "InfoSingleton()" << endl;
	}
	InfoSingleton(const InfoSingleton&) = delete;
	InfoSingleton& operator=(const InfoSingleton& info) = delete;
	map<string, int> _info;
	// ...
private:
};

int main()
{
	InfoSingleton::GetInstance().Insert("张三", 10000);
	InfoSingleton& infosl = InfoSingleton::GetInstance();
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);

	infosl.Print();
	cout << endl;
	InfoSingleton::GetInstance().Insert("张三", 18000);
	infosl.Insert("李四", 12000);
	infosl.Insert("王五", 15000);
	infosl.Insert("赵六", 11000);
	infosl.Print();
	return 0;
}

到了这里,关于【C++修炼之路】33.特殊类设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++中特殊类的设计与单例模式的简易实现

    对于这种特殊类的设计我们一般都是优先考虑私有构造函数。 然后对于一些特殊要求就直接通过静态成员函数的实现来完成。  这里选择禁掉拷贝构造函数和拷贝函数是为了防止将已创建的对象去拷贝构造新的对象。  这里如果没有禁掉operator new和operator delete的话就会导致以

    2024年01月18日
    浏览(47)
  • 从C语言到C++_37(特殊类设计和C++类型转换)单例模式

    目录 1. 特殊类设计 1.1 不能被拷贝的类 1.2 只能在堆上创建的类 1.3 只能在栈上创建的类 1.4 不能被继承的类 1.5 只能创建一个对象的类(单例模式)(重点) 1.5.1 饿汉模式 1.5.2 懒汉模式 2. 类型转换 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3. RTTI(了解)和类型转换常见面

    2024年02月10日
    浏览(49)
  • 【重点:单例模式】特殊类设计

    方式如下: 将构造函数设置为私有,防止外部直接调用构造函数在栈上创建对象。 向外部提供一个获取对象的static接口,该接口在堆上创建一个对象并返回。 将拷贝构造函数设置为私有,并且只声明不实现,防止外部调用拷贝构造函数在栈上创建对象。 说明一下: 向外部

    2024年02月15日
    浏览(46)
  • 特殊类的设计(含单例模式)

    拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此 想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 C++98: 将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。 原因: 设置成私有:如

    2024年01月23日
    浏览(50)
  • 【C++】设计模式-单例模式

    目录 一、单例模式 单例模式的三个要点 针对上述三要点的解决方案 常用的两类单例模式  二、懒汉模式实现 1.基本实现 2.锁+静态成员析构单例 3.双层检查锁定优化 4.双层检查锁定+智能指针 三、饿汉模式实现 1.基础实现 2.嵌套内部类解决内存泄漏 3.智能指针解决内存泄漏

    2024年02月16日
    浏览(38)
  • C++设计模式:单例模式(十)

    1、单例设计模式 单例设计模式,使用的频率比较高,整个项目中某个特殊的类对象只能创建一个 并且该类只对外暴露一个public方法用来获得这个对象。 单例设计模式又分懒汉式和饿汉式,同时对于懒汉式在多线程并发的情况下存在线程安全问题 饿汉式:类加载的准备阶段

    2024年04月14日
    浏览(47)
  • 【设计模式】C++单例模式详解

    ⼀个类仅有⼀个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。 那么,我们必须保证: 该类不能被复制;也不能被公开的创造。 对于 C++ 来说,它的构造函数,拷贝构造函数和赋值函数都不能被公开调用。 单例模式又分为 懒汉模式 和 饿汉模式 ,它们

    2024年02月05日
    浏览(48)
  • C++设计模式代码--单例模式

    参考:5. 单例模式(Singleton) (yuque.com) 1、什么是单例模式 保证一个类只有一个实例,并提供一个访问该实例的全局节点; 2、什么情况下需要单例模式 某个类的对象在软件运行之初就创建,并且在软件的很多地方都需要读写这个类的信息;使用单例模式的话,类对象就只要

    2024年02月03日
    浏览(63)
  • c++设计模式之单例模式

    一个类无论创建多少对象 , 都只能得到一个实例 如上述代码中,我们通过new运算符创建出了类A的三个对象实例,而我们现在要做的是,如何设计类A,使得上述代码运行之后永远只产生同一个对象实例         我们知道,一个类对象是通过这个类的构造函数创建的,因此

    2024年01月19日
    浏览(57)
  • C++设计模式创建型之单例模式

    一、概述         单例模式也称单态模式,是一种创建型模式,用于创建只能产生一个对象实例的类。例如,项目中只存在一个声音管理系统、一个配置系统、一个文件管理系统、一个日志系统等,甚至如果吧整个Windows操作系统看成一个项目,那么其中只存在一个任务管理

    2024年02月14日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包