35.特殊类设计

1.要求设计一个类,允许其只能在堆上创建

(1).将构造方法声明为私有

(2).将构造方法delete(C++11标准才支持),但是如果delete之后new也是不能正常创建对象的,所以此方法是错误的。
#include <iostream>
using namespace std;
class Test
{
public:
	static Test* CreateInstance()  //要在堆上实例化对象,就得依靠这个静态方法
	{
		return new Test;
	}
	//Test(const Test &) = delete;
private:
	Test(){ }  //将构造函数声明为私有
private:
	int a = 0;
	int b = 0;
};

void main()
{
	Test t = Test::CreateInstance();
}
</pre>

2.要求设计一个类,不允许堆上创建

(1)私有化构造函数,静态方法按值返回栈上创建的对象(按值返回调用的是拷贝构造方法,所以拷贝构造必须公有)

#include <iostream>
using namespace std;
class Test
{
public:
	static Test CreateInstance()
	{
		return Test();
	}
	Test(const Test& c) {};  //将拷贝构造函数声明为公有
private:
	Test() { }  //将构造函数声明为私有
private:
	int a = 0;
	int b = 0;
};

int main()
{
	Test t = Test::CreateInstance();
	return 0;
}

(2)重载操作符new,并给为私有属性( 考虑:要防止定位new吗? )

#include <iostream>
using namespace std;
class Test {
private:
	void* operator new(size_t sz) {};
private:
	int a = 0;
	int b = 0;
};
int main() {

	return 0;
}

3.要求设计一个类,不允许对象拷贝

(1)将拷贝构造方法声明为私有

#include <iostream>
using namespace std;
class Test {
public:
	Test()= default;
private:
	Test(const Test& t) {};
private:
	int a = 0;
	int b = 0;
};
int main() {
	Test t1;
	//Test t2 = t1;
	Test t3;
	t3 = t1;  //对象赋值
	return 0;
}

(2).根据C++ 11标准,利用delete关键字删除函数

#include <iostream>
using namespace std;
class Test {
public:
	Test() = default;
	Test(const Test& t) = delete;
private:
	int a = 0;
	int b = 0;
};
int main() {
	Test t1;
	//Test t2 = t1;
	Test t3;
	t3 = t1;  //对象赋值
	return 0;
}

(3).通过继承构造方法是私有属性的类,从而达到不能拷贝的目的

#include <iostream>
#include <boost/utility.hpp>
using namespace std;
class Test : public boost::noncopyable {

};
int main() {
	Test t1;
	//Test t2 = t1;  //不能拷贝构造,派生类要拷贝构造就得先拷贝构造基类
	return 0;
}

原理如下:

boost中将noncopyable的拷贝构造函数声明为了私有

class noncopyable
  {
   protected:
      noncopyable() {}
      ~noncopyable() {}
   private:  // emphasize the following members are private
      noncopyable( const noncopyable& );
      const noncopyable& operator=( const noncopyable& );
  };

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

(1).构造函数私有化,派生类中调不到基类的构造函数,则无法继承

class NonInherit
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit()
	{}
};

(2).借助C++ 11中的final关键字,final修饰类,表示该类不能被继承。

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

5.设计一个类,只能创建一个对象(单例模式)

我们首先实现只允许创建一个对象,不考虑线程安全

//只允许创建一个对象
#include <iostream>
using namespace std;
class Test {
public:
	static Test* creatInstance() {
		if (soleInstance == nullptr) 
			soleInstance = new Test;
		return soleInstance;
	}
private:
	Test() {};
private:
	static Test* soleInstance;
};
Test* Test::soleInstance = nullptr;  //静态成员类外声明

int main() {
	Test* p = Test::creatInstance();
	Test* p1 = Test::creatInstance();
	Test* p2 = Test::creatInstance();
	return 0;
}

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

单例模式可分为懒汉模式和饿汉模式

饿汉模式:程序启动时就创建一个唯一的实例对象

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		return &m_instance;
	}
private:
	// 构造函数私有
	Singleton(){};

	// C++98 防拷贝
	Singleton(Singleton const&);
	Singleton& operator=(Singleton const&);
	// or
	// C++11
	//Singleton(Singleton const&) = delete;
	//Singleton& operator=(Singleton const&) = delete;

private:
	static Singleton m_instance;
};

Singleton Singleton::m_instance;

缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定

懒汉模式实际上相对于饿汉模式是一种延迟加载的方式

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

优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。

#include <iostream>
using namespace std;
class Singleton {
public:
	static Singleton* getInstance() {
		if (nullptr == _singleton)
			_singleton = new Singleton;
		return _singleton;
	}
private:
	Singleton() {};
private:
	static Singleton* _singleton;
};

Singleton* Singleton::_singleton = nullptr;

以上两种单例模式的实现不是线程安全的,创建一个对象本身不是原子操作,主要包含两个操作:分配内存空间,引用变量指向内存。在创建实例的静态方法中必须保证创建对象操作的原子性,才能保证线程安全和逻辑的正确性。

以懒汉模式为例如下:

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
class Singleton {
public:
	static Singleton* GetInstance() {
		// 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全
		if (nullptr == _singleton) {
			_mt.lock();
			if (nullptr == _singleton) {
				_singleton = new Singleton();
			}
			_mt.unlock();
		}
		return _singleton;
	}
private:
	Singleton() {};
private:
	static Singleton* _singleton;
	static mutex _mt;
};

Singleton* Singleton::_singleton = nullptr;
mutex Singleton::_mt; 
void thread_func(int n)
{
	for (int i = 0; i < n; ++i)
		cout << Singleton::GetInstance() << endl;
}

	
int main() {
	thread t1(thread_func, 10);
	thread t2(thread_func, 10);
	t1.join();
	t2.join();

	cout << Singleton::GetInstance() << endl;
	cout << Singleton::GetInstance() << endl;
	return 0;
}

Double-Check的方式加锁,既能保证效率又能保证线程安全

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值