特殊类的实现

目录

1. 只能在堆上创建的类

2. 仅在栈上创建对象

3. 禁止拷贝的类

4. 不能被继承的类

只能创建一个对象的类--单例模式

饿汉模式

懒汉模式

饿汉懒汉的比较


在项目中总会有许多特殊的要求,而我们需要掌握一些特殊类的设计来满足需求。

一般我们设计的类,创建的对象可以在栈区,堆区,静态区,如何设计一些只能在一个存储区创建对象的类呢:

1. 只能在堆上创建的类

首先将构造函数私有化,防止直接在栈区和静态区创建对象,既然我们是在堆上创建,那么一定是动态开辟出来的对象,我们创建 CreateObj函数 用来返回动态开辟出的对象即可。

这样做还有一个问题,就是当我们调用创建对象的函数时,调用函数必须通过对象调用,而我们的对象还没有创建出来,相当于先有鸡还是先有蛋的问题。解决这个问题的突破口就是用 static 修饰创建对象的函数即可。

别忘记将拷贝构造函数设置成为删除函数,防止有人用 copy函数在栈上拷贝出对象

//仅在堆上创建对象
class HeapOnly
{

public:
	static HeapOnly* CreateObj()
	{
		return new HeapOnly;
	}

	//防止老六用 copy 函数
	HeapOnly(HeapOnly& h) = delete;
private:
	//构造函数私有
	HeapOnly()
	{}

};

int main()
{
	//HeapOnly h1;       //栈
	//static HeapOnly h2;   //静态区
	//HeapOnly* ph3 = new HeapOnly;   //堆

	HeapOnly* ph4 = HeapOnly::CreateObj();      
		//调用函数必须有对象,而要有对象那么必须调函数,解决方法:函数前static修饰

	return 0;
}

2. 仅在栈上创建对象

仅在栈上创建对象,那么构造函数私有化,防止在静态区创建对象,创建 CreateObj 函数,返回在栈上创建的对象,同样的将拷贝构造设置成为删除函数

函数中对象还没有创建,返回对象时进行构造,一次拷贝构造,将临时变量赋值给 s1 时,也是一次拷贝构造,但是拷贝构造已经被设置成为了删除函数,按理说应该会报错,这里编译器会将连续的构造和拷贝构造优化成一次直接构造。

//仅在栈上创建对象
class StackOnly
{

public:
	static StackOnly CreateObj()
	{
		return StackOnly();       //栈;   编译器直接优化成一次构造
	}


	//防止老六用 copy 函数
	StackOnly(const StackOnly& h) = delete;

private:
	//构造函数私有
	StackOnly()
	{}

};

int main()
{
	StackOnly s1 = StackOnly::CreateObj();       //栈

	//static StackOnly s2;   //静态区
	//StackOnly* ph3 = new StackOnly;   //堆

	return 0;
}

3. 禁止拷贝的类

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

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

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


C++11中:直接用delete将拷贝构造和赋值运算符重载设置成删除函数,就是不会调用这两个函数的意思,就可以防止对象的拷贝

//禁止拷贝的类
class CopyBan
{
public:
	CopyBan(){}
	CopyBan(const CopyBan&) = delete;
	CopyBan& operator=(const CopyBan&) = delete;
private:
	
};

int main()
{
	CopyBan c1;
	CopyBan c2 = c1;  //这里会报错
	return 0;
}

4. 不能被继承的类

c++98中是直接将构造函数私有化,间接的体现出此类不能被继承

//不能被继承的类
//98是构造函数私有化
class NonInherit
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit()
	{}
};

class A : public NonInherit
{
};
int main()
{
	A a;
	return 0;
}

c++11中直接给我们提供了关键字:final

直接在类名后修饰即可保证此类不能被继承。

//c++11
class NonInherit final
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit()
	{}
};

class A : public NonInherit
{
private:
	int _a;
};
int main()
{
	A::GetInstance();
	return 0;
}

只能创建一个对象的类--单例模式

一个类只能创建一个对象,即单例模式

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

饿汉模式

程序启动时就创建一个唯一的实例对象

首先构造函数私有化,

在成员中创建一个静态的对象,对象是在静态区的,在类中声明,只是受到类域的限制而已,此对象并不是类中的对象;

为什么不将静态成员放在全局,因为构造函数私有,不能访问

静态成员在类中声明,类外定义

class InfoMgr     //---饿汉举例
{
public:
	static InfoMgr* GetInstance()      //调用函数返回唯一对象
	{
		return _spinst;
	}

	void Setaddress(const string& s)
	{
		_address = s;
	}

	string& Getaddress()
	{
		return _address;
	}

private:
	InfoMgr()      //构造函数私有化
	{}
    InfoMgr(const InfoMgr&) = delete;    //防拷贝

	string _address;
	int _secretKey;

	static InfoMgr* _spinst;      //声明
};
InfoMgr* InfoMgr::_spinst = new InfoMgr;   //定义

int main()
{
	InfoMgr::GetInstance()->Setaddress("重庆");
	cout << InfoMgr::GetInstance()->Getaddress() << endl;
	return 0;
}

懒汉模式

第一次使用实例对象时,创建对象。

与饿汉不同的地方就在对象的定义及调用 GetInstance函数时才创建对象

class InfoMgr     //---懒汉举例
{
public:
	static InfoMgr* GetInstance()
	{
		if (_spinst == nullptr)
		{
			_spinst = new InfoMgr;
		}
		return _spinst;
	}

	void Setaddress(const string& s)
	{
		_address = s;
	}

	string& Getaddress()
	{
		return _address;
	}

private:
	InfoMgr()
	{}
    InfoMgr(const InfoMgr&) = delete;    //防拷贝
	string _address;

	static InfoMgr* _spinst;  
};
InfoMgr* InfoMgr::_spinst = nullptr;

int main()
{
	InfoMgr::GetInstance()->Setaddress("重庆涪陵");
	cout << InfoMgr::GetInstance()->Getaddress() << endl;
	return 0;
}

饿汉懒汉的比较

饿汉特点:简单些,初始化顺序不确定,如果有依赖关系就会有问题。饿汉对象初始化慢且多个饿汉单例对象会影响程序启动。(对象多的时候启动程序加载过长)

懒汉特点:复杂一点。第一次调用时初始化,可以控制初始化顺序,延迟加载初始化,不影响程序启动(程序启动速度快)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今年依旧去年春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值