c++笔记(5)

1.拷贝构造

浅拷贝问题:编译器默认提供拷贝构造,是一个拷贝
  1.当类中有指针成员并new了一个空间,会导致多次回收,程序崩溃
  2.当类中有指针成员并new了一个空间,当用一个对象修改指针指向空间的值,其他对象使用的是修改之后的值,导致程序逻辑错误

  解决浅拷贝的问题
  1.需要手动重构拷贝构造函数实现深拷贝(为里面的指针成员单独开辟一个空间,并将指针的值传递过来
  2.避免浅拷贝的发生,函数尽量使用引用或者指针

如果是 new 出来的空间,那么对导致多个对象回收同一块内存空间,引起非法操作错误。
解决办法: 深拷贝 ,它并不是一个固定的写法,而是一个解决的办法:即在拷贝构造时,如果
参数对象中的指针成员指向了一个内存空间,那么在重构拷贝构造时,需要为当前 this 对象中
指针成员额外开辟新的内存空间,并初始化对应的值。
在某些情况下,可以使用 指针或引用 可以避免对象的值传递,也避免了浅拷贝问题。

拷贝构造函数:函数名为当前名,参数当前类对象的引用
编译器默认提供的函数体代码不为空,参数对象里的成员给this对象中的成员依次初始化

如果手动重构了拷贝构造函数,编译器不在提供默认的拷贝构造

class CTest {
public:
	int m_a;
	int* m_p;
	CTest(int a ) {//构造函数只有一个参数,或多个参数且有默认值
		m_a = a;
		m_p = new int(1);
	}
	CTest(const CTest& tst)
	{
		m_a = tst.m_a;
		//this->m_p = tst.m_p;浅拷贝会出问题
		if (tst.m_p) {//这种方法是深拷贝,自己又建立了一个新的空间
			this->m_p = new int(*tst.m_p);
		}
		else {
			this->m_p = nullptr;
		}

	}
	~CTest() {
		delete m_p;//浅拷贝构造,执行之后会有多次的回收,第一次已经被回收了,第二次回收就会出问题
		m_p = nullptr;
	}
};
void show(CTest &tst) {

}

int main() {

	CTest tst(10);
	
	/*
	*EXPLICIT   CTest(int a ) 禁止使用隐式转换
	* 	m_a = a;
	*/

	CTest tst2(tst);//调用拷贝构造
	*tst.m_p = 100;
	cout << *tst.m_p << "  " << *tst2.m_p << endl;//浅拷贝:修改当前值,也会改变浅拷贝对的值||||深拷贝:不能修改当前的值
	show(tst);
	system("pause");
	return 0;

2.隐式类型转换

/*
类中会存在默认的operator=(const CTest &),编译器会默认给提供
*/
/*
空类中,有哪些默认的函数
默认无参数构造函数
默认的析构函数
拷贝构造
默认的operator=(const ctest &)
*/

#include<iostream>
using namespace std;

class CTEST {
public:
	int m_a;
	int* m_p;
	CTEST(int a)
	{
		m_a = a;
		m_p = new int(10);
	}
	CTEST& operator =(const CTEST& tst) {
		cout << "operator =" << endl;
		this->m_a = tst.m_a;
		this->m_p = tst.m_p;
		return *this;
	}
	~CTEST()
	{
		if (m_p)
		{
			delete m_p;
		}
	}
};

int main() {
	CTEST tst1(10);
	/*
	CTEST tst3=20;
	tst3=40;
	*/
	
	system("pause");
	return 0;
}

3.设计模式

1.sington

/*
* 设计模式:前任总结的经验规则,经过分类,编排形成而一套针对于程序设计的经验总结
* 它是针对某些重复出现的问题而设计的一套成功有效的解决方案
* 3打雷,创建型模式,结构型模式,行为型模式,23种

* 分类:懒汉式,饿汉式
* 懒汉式:第一次使用该实例时,在创建

* 饿汉式:程序创建之初,不管用不用这个实例,都要提前创建好
*/

/*
单例模式Sington
1.类最多智能创建一个实例
2.类能够自主的创建实例
3.能够向整个系统提供全局的访问接口访问实例

优点:
1.提供了严格的唯一的实力的创建,访问销毁,提高了安全性
2.节约系统支援

*/

(1)第一种方法--过度

class CSington {
private:
	//static int m_count;//表明对该类所有对象这个数据成员都只有一个实例。即该实例归 所有对象共有。
	static CSington* m_pSin;
	CSington()
	{
		m_a = 10;
	}
	CSington(const CSington& sin) {//防止产生拷贝构造,创建新对象
		m_a = sin.m_a;
	}
	~CSington()//防止CSington *pys=new CSington(*psin),创造出新对象
	{

	}
public:
	static CSington* GetSinton() {
		if (m_pSin) {//替换掉了if (m_count >= 1)
			return m_pSin;

		}
		//m_count++;
		m_pSin = new CSington;
		return m_pSin;
	}
	static void  DestroySington(CSington*& pSin) {
		if (m_pSin) {//一次性删永久了,其他指针都无法用了
			delete m_pSin;
			m_pSin = nullptr;
		}
		pSin = nullptr;
	}
public:
	int m_a;

};
//int CSington::m_count = 0;//静态成员进行初始化.利用m_pSin替换
CSington*  CSington::m_pSin=nullptr;
int main01()
{



	CSington* pSin1 = CSington::GetSinton();
	CSington* pSin2 = CSington::GetSinton();
	CSington::DestroySington(pSin1);
	if (pSin1) {
		cout << pSin1->m_a <<"psin1"<< endl;
	}
	if (pSin2) {
		cout << pSin2->m_a << "psin2" << endl;
	}
	return 0;
}

(2)第二种方法---直接

这种方法就要比前一种方便很多,步骤也是简洁了很多

class CSington {
private:
	static CSington* m_pSin;
	CSington()
	{
		m_a = 10;
	}
	CSington(const CSington& sin) {//防止产生拷贝构造,创建新对象
		m_a = sin.m_a;
	}
	~CSington()//防止CSington *pys=new CSington(*psin),创造出新对象
	{

	}
public:
	static CSington* GetSinton() {//比较与第一张方法,更简单,并且解决了destroy一次性解决所有指针的情况
		static CSington sin;//静态成员对象:只能创建出一个对象,第二个创建不出来,从程序开始生成,一直保留到程旭结尾
		return &sin;
	}

public:
	int m_a;

};
int main02()
{
	CSington* pSin1 = CSington::GetSinton();
	CSington* pSin2 = CSington::GetSinton();
	
	if (pSin1) {
		cout << pSin1->m_a << "psin1" << endl;
	}
	if (pSin2) {
		cout << pSin2->m_a << "psin2" << endl;
	}
	
	return 0;
}

(3)饿汉式

#include <iostream>
using namespace std;

/*
饿汉式
*/
class CSington {
private:
	static CSington sin;
	static CSington* m_pSin;
	CSington()
	{
		m_a = 10;
	}
	CSington(const CSington& sin) {//防止产生拷贝构造,创建新对象
		m_a = sin.m_a;
	}
	~CSington()//防止CSington *pys=new CSington(*psin),创造出新对象
	{

	}
public:
	static CSington* GetSinton() {//比较与第一张方法,更简单,并且解决了destroy一次性解决所有指针的情况
		
		return &sin;
	}

public:
	int m_a;

};
CSington CSington::sin;


int main()
{
	CSington* pSin1 = CSington::GetSinton();
	CSington* pSin2 = CSington::GetSinton();

	if (pSin1) {
		cout << pSin1->m_a << "psin1" << endl;
	}
	if (pSin2) {
		cout << pSin2->m_a << "psin2" << endl;
	}

	return 0;
}

2.factory

#include<iostream>
#include<string>
using namespace std;

class CEngine{
public:
	virtual void  working()=0;
};
class CEngine2L:public CEngine{
public:
	virtual void  working(){
		cout<<"2.0 自然吸气发动机正在工作,wu~wu~wu~"<<endl;
	}
};
class CEngine2T:public CEngine{
public:
	virtual void  working(){
		cout<<"2.0 涡轮增压发动机正在工作,weng~weng~weng"<<endl;
	}
};

class CCar{
public:
	CEngine * m_pEngine;  //父类发动机指针

	CCar(){
		m_pEngine =  new CEngine2L;
	}
	CCar(string type){
		if(type== "2.0L"){
			m_pEngine =  new CEngine2L;
		}else if(type== "2.0T"){
			m_pEngine =  new CEngine2T;
		}else{
			m_pEngine = nullptr;
		}
	}
	void driving(){
		if(m_pEngine){
			m_pEngine->working();
			cout<<"我的小汽车,正在疯狂的行使中..."<<endl;
			
		}
	
	}

};

int main(){

	CCar bmw;
	bmw.driving();

	CCar benz("2.0L");
	benz.driving();

	system("pause");
	return 0;
}

最后的工程例子,设计一个工厂的类,里面在设计出对应需要的功能,把这个作为一个大类,在定义需要的车,利用指针的传递,将车所需要的类型传到工厂中

#include<iostream>
#include<string>
using namespace std;

class CEngine {
public:
	virtual void  working() = 0;
};
class CEngine2L :public CEngine {
public:
	virtual void  working() {
		cout << "2.0 自然吸气发动机正在工作,wu~wu~wu~" << endl;
	}
};
class CEngine2T :public CEngine {
public:
	virtual void  working() {
		cout << "2.0 涡轮增压发动机正在工作,weng~weng~weng" << endl;
	}
};




class GearBox {
public:
	virtual void  working() = 0;
};
class GearBoxSelfcontrol :public GearBox {
public:
	virtual void  working() {
		cout << "自动档变速在工作" << endl;
	}
};
class GearBoxManual :public GearBox {
public:
	virtual void  working() {
		cout << "手动挡变速在工作" << endl;
	}
};




class CfactoryGearBox
{
public:
	virtual GearBox* CreateGearBox() = 0;

};
class CFactorySeifControl :public Cfactory {
	virtual GearBox* CreateGearBox() {
		return new GearBoxSelfcontrol;
	}
};
class CfactoryManual :public Cfactory {
	virtual GearBox* CreateGearBox() {
		return new GearBoxManual;
	}
};





class Cfactory
{
public:
	virtual CEngine* CreateEngune() = 0;

};
class CFactory2L :public Cfactory {
	virtual CEngine* CreateEngune() {
		return new CEngine2L;
	}
};
class CFactory2T :public Cfactory {
	virtual CEngine* CreateEngune() {
		return new CEngine2T;
	}
};




class CCar {
public:
	CEngine* m_pEngine;  //父类发动机指针

	CCar(Cfactory* pfac) {
		if (pfac) {
			m_pEngine = pfac->CreateEngune();
		}
		else
		{
			m_pEngine = nullptr;
		}
	}

	void driving() {
		if (m_pEngine) {
			m_pEngine->working();
			cout << "我的小汽车,正在疯狂的行使中..." << endl;

		}

	}

};

int main() {
	
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值