C++学习 2018-12-13

本文深入探讨单例模式的实现细节,包括如何确保全局唯一实例的生成与管理,以及如何防止通过拷贝构造和继承破坏单例特性。此外,文章还介绍了模板技术的应用,包括函数模板和类模板,用于实现代码复用和泛型编程,提升软件的灵活性和可维护性。

1.单例模式

1.把bflag放到类中:解决bflag为外部共有变量的问题

1.改为static类型,static bool bflag,并在类外初始化。

#include <iostream>
using namespace std;

// bool bflag = false;				// 在main函数中可以将其重置为false,此时就可以继续生成新的类,不满足单例的要求

class CPerson
{
private:
	static bool bflag;

private:
	CPerson(){}
	~CPerson(){}

public:
	static CPerson* GetObject()
	{
		if(bflag == false)
		{
			bflag = true;
			CPerson *p = new CPerson;
			return p;
		}
		return NULL;
	}
};

bool CPerson::bflag = false;


int main()
{
	CPerson *ps1 = CPerson::GetObject();
	// bflag = false;									// 此时更改bflag的值就可以重新生成一个对象,故需将bflag变为类成员
	CPerson *ps2 = CPerson::GetObject();

	system("pause");
	return 0;
}

2.删除单例后想重新生成一个单例,则在析构函数中进行bflag的更改,该析构是私有的,提供一个DestroyObject接口函数去调用析构函数。

#include <iostream>
using namespace std;


class CPerson
{
private:
	static bool bflag;  // 程序中是否存在对象
private:
	CPerson()
	{
	
	}
	~CPerson()
	{
		
	}
public:
	CPerson(const CPerson& pp)
	{
	
	}
public:
	static CPerson* GetObject()
	{
		if(bflag == false)
		{
			CPerson* p = new CPerson;
			bflag = true;
			return p;
		}
		return NULL;
	}
	static void DestoryObject(CPerson* pObject)
	{
		bflag = false;
		delete pObject;
	}
};
bool CPerson::bflag = false;


int main()
{
	CPerson* p = CPerson::GetObject();

	CPerson* ps = new CPerson(*p);
	

	system("pause");
	return 0;
}

3.经过上述步骤之后,通过拷贝构造仍可创建一个新对象,因此需要将拷贝构造也设计为私有。

#include <iostream>
using namespace std;

class CPerson
{
private:
	static bool bflag;

private:
	CPerson(){}
	~CPerson(){}
	CPerson(const CPerson& ps){}			// 为了解决可以通过CPerson *ps2 = new CPerson(*ps1);生成新的对象的问题,需要将拷贝构造也设置为private
public:
	static CPerson* GetObject()
	{
		if(bflag == false)
		{
			bflag = true;
			CPerson *p = new CPerson;
			return p;
		}
		return NULL;
	}
};

bool CPerson::bflag = false;


int main()
{
	CPerson *ps1 = CPerson::GetObject();

	CPerson *ps2 = new CPerson(*ps1);


	system("pause");
	return 0;
}
2.不允许 A a 生成对象,只允许 new A 生成对象。

考虑:A a生成的对象是系统调用析构函数,即析构函数是公有的,因此将析构函数设置为private即可。

#include <iostream>
using namespace std;

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

};

int main()
{
	AA a;						// 不允许这样生成对象
	AA *p = new AA;				// 允许这样生成对象

	system("pause");
	return 0;
}
3.考虑一个类,怎样可以实现不被继承

考虑:将基类的构造函数设置为 private。

#include <iostream>
using namespace std;

class AA
{
private:
	AA(){}
};

class BB : public AA
{
public:
	BB(){}
};

int main()
{
	// 不想被继承就意味着将构造设置为私有
	BB b;

	system("pause");
	return 0;
}
4.想让3中的AA的构造函数为public且不被继承

考虑:为AA提供一个父类,并在该父类中设置AA为其友元类。

#include <iostream>
using namespace std;

// 意图不被继承则将构造改为private
// 意图构造为public仍不可被继承,则需提供一个父类

class CFather
{
private:
	CFather(){}
public:
	friend class AA;
};

class AA:public CFather
{
public:
	AA(){}
};

class BB : public AA
{
public:
	BB(){}
};

int main()
{
	BB b;

	system("pause");
	return 0;
}

注意:按理说上述代码无法创建 BB b 对象,但实际是可以创建的;
解决方法:将AA类继承的方法改为 virtual public CFather,可以解决该问题。

2.模版方法

1.有三个类,每个类中的某些函数的代码完全一样,可以提供一个父类以供继承来减少代码量。
// 1.有三个类 CChina、CJapen、CUsa,其都具有Eat函数,且其中只有一行代码不同
//   若全部使用源代码会显得繁琐,因此提供一个父类CPerson,来进行复用

// 2.使用上述方法时需注意,不可以在父类的构造函数中使用 this->EatStyle(),
//   因为在父类构造函数执行时,子类并为生成,因而会调用父类的EatStyle,
//   当EatStyle为纯虚函数时会出错
#include <iostream>
using namespace std;

// 父类
class CPerson
{
public:
	virtual void EatStyle()=0;
public:
	virtual void Eat()
	{
		cout << "吃饭" << endl;
		this->EatStyle();
		cout << "吃米饭" << endl;
		cout << "吃饱了" << endl;
		cout << "擦嘴" << endl;
		cout << "洗碗" << endl;
	}
};

class CChina : public CPerson
{
public:
	
	void EatStyle()
	{
		cout << "用筷子" << endl;
	}
};

class CUsa : public CPerson
{
public:
	void EatStyle()
	{
		cout << "用刀叉" << endl;
	}
};

class CJapen : public CPerson
{
public:
	void EatStyle()
	{
		cout << "用手" << endl;
	}
};

int main()
{
	CChina ch;
	ch.Eat();

	CUsa ua;
	ua.Eat();

	CJapen jp;
	jp.Eat();

	system("pause");
	return 0;
}
2.当三个类中大部分代码一样,只有一两行代码不同,可以使用模版方法。
3.当意图在函数中调用子类的函数时,不能使用构造函数去调用,因为此时对象并为创建。

3.函数模版

1.当两个及以上的重载函数中代码一样时,使用模版函数。
// 1.当两个及以上的重载函数中的代码一样,只有数据类型不同时,可以使用模版
//   template<typename TT>
#include <iostream>
using namespace std;

template<typename TT>
void Show(TT t)
{
	cout << t << endl;
}


//void Show(int a)
//{
//	cout << a << endl;
//}
//
//void Show(char *str)
//{
//	cout << str << endl;
//}

int main()
{
	Show(123);
	Show("adfadfasd");
	Show('a');

	system("pause");
	return 0;
}
2.template TT时模版,可以是任意类型,作用域只有紧邻着的函数。
3.冒泡排序

当前只有int类型的排序,若想进行char、double型的排序,需要进行函数重载,但是除了数据类型不同,剩下的完全一样,此时就可以使用函数模版。

// 1.想要完成一个可以对任意类型进行冒泡排序的函数,使用模版
#include <iostream>
using namespace std;

template<typename TT>
void Bubble(TT *p, int n)
{
	for(int i=0; i<n-1; i++)
	{
		for(int j=0; j<n-1-i; j++)
		{
			if(p[j] > p[j+1])
			{
				TT ntemp = p[j];
				p[j] = p[j+1];
				p[j+1] = ntemp;
			}
		}
	}
}

int main()
{
	// int型数组
	int arr1[] = {9, 5, 8, 7, 6, 1, 2, 4, 3, 0};
	Bubble(arr1, 10);
	for(int nvle:arr1)
	{
		cout << nvle << " ";
	}
	cout << endl << "==================================" << endl;

	// double型数组
	double arr2[] = {9.2, 5.5, 8.3, 7.5, 6.4, 1.9, 2.8, 4.1, 3.0, 0.5};
	Bubble(arr2, 10);
	for(double nvle:arr2)
	{
		cout << nvle << " ";
	}
	cout << endl << "==================================" << endl;

	system("pause");
	return 0;
}
4.冒泡排序的升级:可对任意类型、任意方法进行排序

可以使用函数指针达到该目标、或者使用类,进行继承来完成。

// 1.想要完成一个可以对任意类型进行冒泡排序的函数,使用模版
// 2.若想将RuleOfSort和RuleOfUnsort进行复用,则需定义一个父类,定义一个纯虚函数,在定义子类来实现方法,
//   通过调用类对象的成员来进行函数指针的赋值
#include <iostream>
using namespace std;

class RULE
{
public:
	virtual bool Rule()=0;
};

template<typename TT>
void Bubble(TT *p, int n, bool (*pfc)(TT a, TT b))
{
	for(int i=0; i<n-1; i++)
	{
		for(int j=0; j<n-1-i; j++)
		{
			if(pfc(p[j], p[j+1]))
			{
				TT ntemp = p[j];
				p[j] = p[j+1];
				p[j+1] = ntemp;
			}
		}
	}
}

//template<typename TT>
bool RuleOfSort(int a, int b)
{
	return a > b;
}

//template<typename TT>
bool RuleOfUnsort(double a, double b)
{
	return a < b;
}

int main()
{
	// int型数组
	int arr1[] = {9, 5, 8, 7, 6, 1, 2, 4, 3, 0};
	Bubble(arr1, 10, RuleOfSort);
	for(int nvle:arr1)
	{
		cout << nvle << " ";
	}
	cout << endl << "==================================" << endl;

	// double型数组
	double arr2[] = {9.2, 5.5, 8.3, 7.5, 6.4, 1.9, 2.8, 4.1, 3.0, 0.5};
	Bubble(arr2, 10, RuleOfUnsort);
	for(double nvle:arr2)
	{
		cout << nvle << " ";
	}
	cout << endl << "==================================" << endl;

	system("pause");
	return 0;
}

4.类模版

1.在类前添加template,此时声明 CPerson ps 时会报错,需要模版参数列表:CPerson ps。
template<typename TT>
class CPerson
{
public:
	TT m_value;

public:
	CPerson(TT tt)
	{
		m_value = tt;
	}

public:
	void ShowPerson()
	{
		cout << m_value << endl;
	}
};

int main()
{
	CPerson<int> ps(100);
	ps.ShowPerson();
	
	system("pause");
	return 0;
}
2.可以给予多个模板类型。
template<typename TT, typename KK>
class CPerson
{
public:
	TT m_value;
	KK m_value1;

public:
	CPerson(TT tt, KK kk)
	{
		m_value = tt;
		m_value1 = kk;
	}

public:
	void ShowPerson()
	{
		cout << m_value << m_value1 << endl;
	}
};

int main()
{
	CPerson<int, double> ps(100, 1.1);
	ps.ShowPerson();
	
	system("pause");
	return 0;
}
3.可以在模版初始化列表中放类
template<typename TT>
class CPerson
{
public:
	TT m_value;

public:
	CPerson()
	{
	}
};

template<typename KK>
class CAnimal
{
public:
	m_value;
};

int main()
{
	CPerson<CAnimal<int>> ps;

	system("pause");
	return 0;
}
4.创建一个可以装任意类型的链表
template<typename TT>
class CList
{
private:
	struct Node
	{
		TT m_value;
		Node *p_next;
	};

private:
	Node *p_head;
	Node *p_end;
	int m_size;
	
public:
	CList()
	{
		*p_head = 0;
		*p_end = 0;
		m_size = 0;
	}
	CList(int n_count, TT n_value = 0)
	{
		*p_head = 0;
		*p_end = 0;
		m_size = 0;

		for(int i=0; i<nCount; i++)
			Push_Back(nVal);
	}
	~CList()
	{
		while(m_pHead)
			Pop_Front();
	}

public:
	void Push_Back(TT nVal)
	{
		//  创建一个节点  把nVal装进去
		Node* pNode = new Node;
		pNode->nValue = nVal;
		pNode->pNext = 0;

		//  放到链表的尾
		if(m_pHead == 0)
		{
			m_pHead = pNode;
			m_pEnd = pNode;
		}
		else
		{
			m_pEnd->pNext = pNode;
			m_pEnd = pNode;
		}
		//  长度+1
		++m_nSize;
	}

	void Pop_Front()
	{
		//  没有节点
		if(m_pHead == 0)
			return;

		//  有一个
		if(m_pHead->pNext == 0)
		{
			delete m_pHead;
			m_pHead = 0;
			m_pEnd = 0;
			m_nSize = 0;	
		}
		else
		{
			//  两个以上
			Node* pDel = m_pHead;
			m_pHead = m_pHead->pNext;
			delete pDel;
			pDel = 0;
			--m_nSize;
		}
	}

	void Print()
	{
		Node* pTemp = m_pHead;
		while(pTemp != 0)
		{
			cout << pTemp->nValue << " ";
			pTemp = pTemp->pNext;
		}
		cout << " size:" << m_nSize << endl;
	}
};

int main()
{

	CList lst;
	lst.Print();

	CList lst1(3);
	lst1.Print();

	CList lst2(3,123);
	lst2.Print();

	lst.Push_Back(1);
	lst.Push_Back(2);
	lst.Print();

	lst1.Pop_Front();
	lst1.Print();

	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值