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;
}