首页 > 其他分享 >Day3

Day3

时间:2024-02-07 17:56:34浏览次数:14  
标签:调用 函数 对象 Day3 拷贝 Maker 构造函数

1.初始化和清理的概念(了解)

1.当对象产生时,必须初始化成员变量,当对象销毁前,必须清理对象

2.初始化用构造函数,清理用析构函数,这两个函数是编译器调用

2.构造函数和析构函数(重点)

1.初始化的作用和析构函数的作用

构造函数的作用
class Maker
{
public:
	//构造函数的作用是初始化成员变量,是编译器去调用的
	Maker()
	{
		a = 10;
		cout << "构造函数" << endl;
	}

	//析构函数,在对象销毁前,编译器调用析构函数
	~Maker()
	{
		cout << "析构函数" << endl;
	}
public:
	int a;
};

void test01()
{
	//实例化对象,内部做了两件事,1.分配空间,2.调用构造函数进行初始化
	Maker m;
	int b = m.a;
	cout << b << endl;

}

//析构函数的作用
class Maker2
{
public:
	//有参构造
	Maker2(const char *name,int age)
	{
		cout << "有参构造" << endl;
		//从堆区空间申请
		pName = (char*)malloc(strlen(name) + 1);
		strcpy(pName, name);
		mAge = age;
	}

	void printMaker2()
	{
		cout << "name:" << pName << " age:" << mAge << endl;
	}
	~Maker2()
	{
		cout << "析构函数" << endl;
		//释放堆区空间
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
private:
	char *pName;
	int mAge;
};

void test02()
{
	Maker2 m2("翠花",18);
	m2.printMaker2();

}

2.构造函数点和析构函数的注意

​ 1.构造函数和析构函数的权限必须是公有的

​ 2.构造函数可以重载

​ 3.构造函数没有返回值,不能用void,构造函数可以有参数,析构函数没有返回值,不能用void,没有参数

​ 4.有对象产生必然会调用构造函数,有对象销毁必然会调用析构函数。有多少个对象产生就会调用多少次构造函数,有多少个对象销毁就会调用多少次析构函数

3.默认的构造函数和默认的析构函数

class MyClass
{
public:
	MyClass(){}//默认的构造函数,函数体是空的
	~MyClass(){}//默认的析构函数,函数体也是空
    //编译器默认提供默认的构造函数和析构函数
private:

};

3.拷贝函数

1.什么是拷贝构造

class Maker
{
public:
	Maker()
	{
		cout << "无参构造函数" << endl;
		a = 20;
	}
	//拷贝构造函数
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
		a = m.a;
		
	}
	//打印函数
	void printMaker()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};



void test01()
{
	Maker m1;
	m1.printMaker();

	//用一个已有的对象去初始化另一个对象
	Maker m2(m1);
	m2.printMaker();
}

2.编译器提供了默认的拷贝构造函数

class Maker2
{
public:
	Maker2()
	{
		cout << "无参构造函数" << endl;
		a = 20;
	}
	//编译器提供了默认的拷贝构造函数
	//Maker2(const Maker2 &m)
	//{
	//	//默认拷贝构造函数进行了成员变量的简单拷贝
	//	a = m.a;
	//}

	//打印函数
	void printMaker()
	{
		cout << "a=" << a << endl;
	}
private:
	int a;
};


void test02()
{
	Maker2 m1;
	m1.printMaker();

	
	Maker2 m2(m1);
	m2.printMaker();
}

3.拷贝构造函数中形参要用引用

class Maker3
{
public:
	Maker3(int Ma)
	{
		cout << "有参构造函数" << endl;
		ma = Ma;
	}
	Maker3(const Maker3 &m)
	{
		cout << "拷贝构造函数" << endl;
	}
private:
	int ma;
};

void test03()
{
	Maker3 m1(10);//调用有参构造

	Maker3 m2(m1);//调用拷贝构造
    Maker3 m3 = m1; //调用拷贝构造

	//如果拷贝构造函数中的形参不是引用
	/*
	Maker3(const Maker3 m)
	{
		cout << "拷贝构造函数" << endl;
	}

	1.Maker3 m2(m1); //外边
	2.const Maker3 m=m1; //类视为
	3.const Maker3 m(m1); //循环
	4.const Maker3 m=m1;
	5.进入死循环
	*/
}

4.构造函数的分类及调用(重点)

1.构造函数的分类:无参构造函数,有参构造函数,拷贝构造函数

2.类默认提供了哪些函数:默认的构造函数,默认的析构函数,默认的拷贝构造函数,默认的赋值函数

3.构造函数的调用

void test01()
{
	Maker m;//调用无参构造函数
	Maker m1(10);//调用有参构造
	Maker m2(m1);//调用拷贝构造

	//不常用
	Maker m4 = Maker(10);//调用的是有参构造函数
	Maker m3 = m2;//调用拷贝构造 Maker m3(m2);
	Maker m5 = 10;//Maker m5=Maker(10); //调用有参构造
	
	Maker m6;//无参构造
	m6 = m5; //赋值

}

5.匿名对象(了解)

1.匿名对象的生命周期在当前行

void test01()
{
    //当前行结束 直接执行析构函数
	Maker();//匿名对象的生命周期在当前行
	Maker(10);
	

	//注意,如果匿名对象有名字来接,那么就不是匿名对象

	Maker m1 = Maker();

	cout << "test01()函数结束" << endl;
}

6.拷贝构造函数调用的时机(重点)

1.对象以值方式给函数参数

class Maker
{
public:
	Maker()
	{
		cout << "无参构造函数" << endl;
	}
	Maker(int a)
	{
		cout << "有参构造函数" << endl;
	}
	Maker(const Maker &maker)
	{
		cout << "拷贝构造函数" << endl;
	}
	~Maker()
	{
		cout << "析构函数" << endl;
	}
};
//1.对象以值方式给函数参数
void func(Maker m)//Maker m=m1;
{

}

void test01()
{
	Maker m1;
	func(m1);


2.用一个已有的对象去初始化另一个对象

void test02()
{
	Maker m1;
	Maker m2(m1);
}

3.函数的局部对象以值的方式从函数返回,vs Debug(调试)模式下,会调用拷贝构造,vs Release(发行)模式下不会调用拷贝构造,qt也不调用

实际测试 在现版本中 都不调用拷贝函数

Maker func2()
{
	//局部对象
	Maker m;
	cout << "局部对象的地址:" << &m << endl;

	return m;
}

void test03()
{
	
	Maker m1 = func2();

	cout << "m1对象的地址:" << &m1 << endl;
}
-----------------------------------------------------
//无参构造函数!
//被调函数局部对象t1的地址:000000F61813F644
//主调函数局部对象t1的地址:000000F61813F644
//析构函数!
//请按任意键继续. . .
-----------------------------------------------------
//正常应该 但是编译器现执行上述同一个操作对象
//无参构造函数!
//被调函数局部对象t1的地址:00003
//拷贝构造
//析构函数
//主调函数局部对象t1的地址:000000F61813F644
//析构函数!
//请按任意键继续. . .

7.构造函数的调用规则(重点难点)

1.如果程序员提供了有参构造,那么编译器不会提供默认构造函数,但是会提供默认的拷贝构造

void test01()
{
	//Maker m;//err

	//Maker m(10);//调用有参构造
	//Maker m2(m);//调用默认的拷贝构造
}

2.如果程序员提供了拷贝构造函数,那么编译器不会提供默认的构造函数和默认的拷贝构造函数

void test02()
{
	Maker m; //error
}

9.多个对象的构造和析构(重点难点)

1.如果类有成员对象,那么先调用成员对象的构造函数,再调用本身的构造函数,析构函数的调用顺序反之
2.成员对象的构造函数调用和定义顺序一样
3.注意,如果有成员对象,那么实例化对象时,必须保证成员对象的构造和析构能被调用

class BMW
{
public:
	BMW()
	{
		cout << "BMW构造" << endl;
	}

	~BMW()
	{
		cout << "BMW析构" << endl;
	}
};

class Buick
{
public:
	Buick()
	{
		cout << "Buick构造" << endl;
	}

	~Buick()
	{
		cout << "Buick析构" << endl;
	}
};

class Maker
{
public:
	Maker()
	{
		cout << "Maker构造" << endl;
	}

	~Maker()
	{
		cout << "Maker析构" << endl;
	}
private:
	
	Buick bui;//成员对象
	BMW bmw;//成员对象
};

void test01()
{
	Maker m;
}

2.初始化列表

1.初始化列表是干什么用的,指定调用成员对象的某个构造函数

2.初始化列表只能写在构造函数

3.如果使用了初始化列表,那么所有的构造函数都要写初始化列表

4.如果有多个对象需要指定调用某个构造函数,用逗号隔开

5.可以使用对象的构造函数传递数值给成员对象的变量

class BMW2
{
public:

	BMW2(int a)
	{
		cout << "BMW2有参构造" << a << endl;
	}

	~BMW2()
	{
		cout << "BMW2析构" << endl;
	}
};

class Buick2
{
public:
	Buick2(int b,int c)
	{
		cout << "Buick2构造" << endl;
	}

	~Buick2()
	{
		cout << "Buick2析构" << endl;
	}
};

class Maker2
{
public:
	//初始化列表
	//注意1:初始化列表只能写在构造函数
     Maker2() :bmw(10)
	{
		cout << "Maker2构造" << endl;
    }
    /*
     Maker2 m;
    */
	//如果有多个对象需要指定调用某个构造函数,用逗号隔开
	Maker2(int a,int b,int c) :bmw(a), bui(b,c)
	{
		cout << "Maker2构造" << endl;
	}
     /*
      Maker2 m(10,20,30);
    */
	//注意2:如果使用了初始化列表,那么所有的构造函数都要写初始化列表
	Maker2(const Maker &m2) :bmw(40), bui(10,20)
	{

	}
private:

	Buick2 bui;//成员对象
	BMW2 bmw;//成员对象
};

10.对象的深浅拷贝(重点难点)

1.默认的拷贝构造函数进行了简单的赋值操作(浅拷贝)

2.浅拷贝的问题

同一块空间被释放两次

class Student
{
public:
	Student(const char *name, int Age)
	{
		pName = (char*)malloc(strlen(name) + 1);
		strcpy(pName, name);
		age = Age;
	}

	~Student()
	{
		cout << "析构函数" <<endl;
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}
public:
	char *pName;
	int age;
};

void test02()
{
	Student s1("小花", 18);
	Student s2(s1);

	cout << "s1 Name=" << s1.pName << " s1 age=" << s1.age << endl;
	cout << "s2 Name=" << s2.pName << " s2 age=" << s2.age << endl;
}

3.深拷贝解决浅拷贝问题

自己写拷贝构造函数

	//深拷贝
	Student(const Student &stu)
	{
		cout << "自己的拷贝构造函数" << endl;
		//1.申请空间
		pName = (char*)malloc(strlen(stu.pName) + 1);
		//2.拷贝数据
		strcpy(pName, stu.pName);
		age = stu.age;
	}

标签:调用,函数,对象,Day3,拷贝,Maker,构造函数
From: https://www.cnblogs.com/wbcde116/p/18011149

相关文章

  • 寒假day3 2.4
    讲师:钟皓曦,NOI2012Au,from成都七中听课能听懂30%就算成功**dp关键:状态、转移、初始化转移:状态与状态之间的关系初始化:状态的边界条件数字三角形状态:\(f_{i,j}\)表示走到\(a_{i,j}\)这个位置的最大价值。如何设计状态?题目要你干什么——从第一行走到最后一行该过程......
  • 代码随想录 day39 不同路径 不同路径 II
    不同路径这题由于说明了只能向下和向右那么对于终点而言显然只能由[i][j-1]+[i-1][j]种路线这就是状态转移方程那么初始值要赋予的就是上边和左边都是一也就是直接从边边到达重点的这样就保证我们的状态转移方程有数值可以将计算不同路径II这题难解的点在于障......
  • 代码随想录 day37 单调递增的数字 监控二叉树
    单调递增的数字只想到暴力解法然后超时这里思路是如果从后往前发现不是递增序列那就把前一位--后一位数字变成9然后维护这个变成9的坐标遍历完后把后面的也全部变成9这个对现在的我来说太难了先贴段代码理解一下吧classSolution{intres=0;publicintminCam......
  • 代码随想录 day36 无重叠区间 划分字母区间 合并区间
    无重叠区间这里的思路是找到有几个非重叠区间然后总数减去非重叠区间就是剩下的重叠区间数首先排好序按左或者右都可以这里按左排好然后发现边界不重叠就++边界重叠那么由于左边界优先对齐了所以右边界更新作为一个新的整体区间和下一个区间比较划分字母区间......
  • 代码随想录 day35 柠檬水找零 根据身高重建队列 用最少数量的箭引爆气球
    柠檬水找零就根据几种条件列出来找零情况就行生活经验可知找零当然先给大面额的利于后面的找零根据身高重建队列这题感觉就是先做过队列给糖也难以有思路这里是先按身高先排好队一样身高就k小的排在前面然后再按他前面有几个人直接就给他插到第几个位置就行用最少......
  • 代码随想录 day34 K 次取反后最大化的数组和 加油站 分发糖果
    K次取反后最大化的数组和按照元素的绝对值大小进行排序把绝对值大的且小于0的取反如果还能取反那么奇数次的话就把绝对值小的取反偶数次不用管加油站首先如果总油量小于总消耗是一定不能跑完的这里的思路是如果[0,i]区间不能油量小于消耗那么就尝试从下一个i+1......
  • 代码随想录 day32 买卖股票的最佳时机 II 跳跃游戏 跳跃游戏 II
    买卖股票的最佳时机II代码非常简单但是想不到思路就比较难这里是这样的逻辑若在d4卖出d1买入获得收益那么实际可以拆解成d4-d3+d3-d2+d2-d1也就是d4-d1实际就是变成看明天减去今天收益是不是大于0就行亏钱就不要赚钱就要跳跃游戏一步步跟着跳就是看......
  • Day3
    publicclassTest01{publicstaticvoidmain(String[]args){//二元运算符inta=10;intb=20;intc=25;intd=25;System.out.println(a+b);System.out.println(a-b);System.out.println(a*b);......
  • 代码随想录 day30 回溯算法最高难度
    重新安排行程这个是关键然后利用数组或者map记录映射关系trueorfalse记录飞没飞过去重因为起飞和落地都可能重复有恰好tickets+1个地点就行这个代码比较贴近cpp的思路但是会超时这个用map的比较节约时间n皇后难点在于模拟棋盘数据处理以及回溯算法能不能......
  • winter 2024 day3
    SMUWinter2024round1AB.SumofMedians思路:贪心的想,只有中位数有贡献,并且知道了中位数的位置以及中位数左边的数的个数l和中位数右边的数的个数r,那么对于一个不递减的数组,要取出最大的中位数,即取出l个最小的数和r个最大的数,中位数即为第r+1大的数。直到数取完为止。......