构造函数和析构函数

O创建一个Score类,完成以下功能:
O连续输入多位学生的float成绩(成绩=科目A成绩+科目B成绩+科目C成绩) ;
O学生数目可以由用户自定义(默认为2个,最多为100个) ;
O显示每位同学的每科成绩和平均分;
O显示每门科目的平均成绩;
O对每门成绩进行排序并由高到低显示;
O对整个文件进行打包。

创建grade.h和grade.cpp文件,在grade.h中编入代码,是关于类与函数的声明:

#ifndef GRADE_H_H
#define GRADE_H_H
#include<string>
#include<iostream>
using namespace std;
class score {
private:
	float grade[100][100];
	int times;
	string name[100];
public:
	score();
	score(int times1);
	~score();
	void inputscore();
	void showscore();
	void showStuAvgScore();
	void showSubAvgScore();
	void sortSub();

};
#endif

 在grade.cpp中进行类中函数的定义;

#include"grade.h"
using namespace std;
//string name[100];
	score::score()
	{
		times = 2;
		cout << "默认学生为2" << endl;
	}
	score::score(int times1)
	{
		times = times1;
		cout << "自定学生人数" << endl;
	}
	score::~score()
	{
		cout << "~score" << endl;
	}
	
	void score::inputscore()
	{
		for (int i = 0; i < times; i++)
		{
			cout << "输入学生姓名" << endl;
			cin >> name[i];
			cout << "输入科目A成绩" << endl;
			cin >> grade[i][0];
			cout << "输入科目B成绩" << endl;
			cin >> grade[i][1];
			cout << "输入科目C成绩" << endl;
			cin >> grade[i][2];
		}
	}
	void score::showscore()
	{
		for (int i = 0; i < times; i++)
		{
			cout << "学生姓名是" << name[i] << endl;
			cout << "科目A成绩是" << grade[i][0] << endl;
			cout << "科目B成绩是" << grade[i][1] << endl;
			cout << "科目C成绩是" << grade[i][2] << endl;

		}
	}
	void score::showStuAvgScore()
	{
		//float avg = 0;
		for (int i = 0; i < times; i++)
		{
			float avg = 0;
			for (int j = 0; j <= 2; j++)
			{
				avg = avg + grade[i][j];
			}
			avg = avg / 3;
			cout << name[i] << "同学的平均值是" << avg << endl;
		}
	}
	void score::showSubAvgScore()
	{
		float avgA = 0;
		float avgB = 0;
		float avgC = 0;
		for (int i = 0; i < times; i++)
		{
			avgA = avgA + grade[i][0];
			avgB = avgB + grade[i][1];
			avgC = avgC + grade[i][2];
		}
		avgA = avgA / times;
		avgB = avgB / times;
		avgC = avgC / times;
		cout << "科目A的平均分是" <<avgA<< endl;
		cout << "科目B的平均分是" << avgB << endl;
		cout << "科目C的平均分是" << avgC << endl;

	}
	void score::sortSub()
	{
		float temp;
		for (int i = 0; i <= 2; i++)
		{
			for (int j = 1; j < times; j++)
			{
				if (grade[j][i] > grade[j - 1][i])
				{
					temp = grade[j][i];
					grade[j][i] = grade[j - 1][i];
					grade[j - 1][i] = temp;
				}

			}
			for (int j = 0; j < times; j++)
			{
				cout << grade[j][i] << " ";
			}
			cout << endl;
		}
	}

在main.cpp中编入主函数:

#include"main.h"
int main()
{
	score x(3);
	x.inputscore();
	x.showscore();
	x.showStuAvgScore();
	x.showSubAvgScore();
	x.sortSub();
	return 0;
}

针对排序函数有其他的基本排序方式如插入排序,选择排序等,此文件中选用的是冒泡法排序。

1.冒泡法排序:

  1. 从第一个和第二个开始比较,如果第一个比第二个大,则交换位置,然后比较第二个和第三个,逐渐往后

  2. 经过第一轮后最大的元素已经排在最后,所以重复上述操作的话第二大的则会排在倒数第二的位置。

  3. 那重复上述操作n-1次即可完成排序,因为最后一次只有一个元素所以不需要比较。

代码实现如下:

void score::sortSub()
	{
		float temp;
		for (int i = 0; i <= 2; i++)
		{
			for (int j = 1; j < times; j++)
			{
				if (grade[j][i] > grade[j - 1][i])
				{
					temp = grade[j][i];
					grade[j][i] = grade[j - 1][i];
					grade[j - 1][i] = temp;
				}

			}
			for (int j = 0; j < times; j++)
			{
				cout << grade[j][i] << " ";
			}
			cout << endl;

        冒泡排序是一种简单直接暴力的排序算法,每一轮比较可能多个元素移动位置,而元素位置的互换是需要消耗资源的,所以这是一种偏慢的排序算法,仅适用于对于含有较少元素的数列进行排序。

      稳定性:我们从代码中可以看出只有前一个元素大于后一个元素才可能交换位置,所以相同元素的相对顺序不可能改变,所以它是稳定排序。

      比较性:因为排序时元素之间需要比较,所以是比较排序。

      时间复杂度:因为它需要双层循环n*(n-1)),所以平均时间复杂度为O(n^2)。

      空间复杂度:只需要常数个辅助单元,所以空间复杂度为O(1),我们把空间复杂度为O(1)的排序成为原地排序(in-place)。

2.选择排序

        选择排序是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,所以称为:选择排序

1.设第一个元素为比较元素,依次和后面的元素比较,比较完所有元素找到最小的元素,将它和第一个元素互换

2.重复上述操作,我们找出第二小的元素和第二个位置的元素互换,以此类推找出剩余最小元素将它换到前面,即完成排序。代码实现:

void score::sortSub()
	{
		float temp;
		for (int i = 0; i <= 2; i++)
		{
			for (int j = 0; j < times-1; j++)
			{
                for(int k=j+1,biggest=j;k<times;k++)
				if (grade[k][i] > grade[biggest][i])
				{
					biggest=k;
                swap(grade[k][i],grade[biggest][i])
				}

			}
			for (int j = 0; j < times; j++)
			{
				cout << grade[j][i] << " ";
			}
			cout << endl;

         选择排序和冒泡排序很类似,但是选择排序每轮比较只会有一次交换,而冒泡排序会有多次交换,交换次数比冒泡排序少,就减少cpu的消耗,所以在数据量小的时候可以用选择排序,实际适用的场合非常少。

比较性:因为排序时元素之间需要比较,所以是比较排序

稳定性:因为存在任意位置的两个元素交换,所以为不稳定排序

时间复杂度:我们看到选择排序同样是双层循环n*(n-1)),所以时间复杂度也为:O(n^2)

空间复杂度:只需要常数个辅助单元,所以空间复杂度也为O(1)

心得体会
 

        1.在debug中,在grade.h文件中进行类的声明后,我在grade.cpp中进行类的定义,编译后出现错误:score class重复定义。经过搜索之后,执行grade.cpp源文件中的代码,#include"grade.h"此句代码,编译器回去查找grade.h头文件,发现score这个类已经定义,继续执行,在下面我又进行了score的定义,导致debug报错。于是在grade.cpp中,删除了class score,直接进行函数的定义,调整之后程序正常运行,代码如下:

score::score()
	{
		times = 2;
		cout << "默认学生为2" << endl;
	}
	score::score(int times1)
	{
		times = times1;
		cout << "自定学生人数" << endl;
	}
	score::~score()
	{
		cout << "~score" << endl;
	}

2.在grade.h文件中,进行string name[100]声明,debug会出现以下错误:string未定义;

        经过搜索之后,需要在声明string name[100]之前使用using namespace std;语句,头文件中不仅要包含<string>,也要加上命名空间。除了使用using namespace std;之外,还可以使用std::string,来解决问题。

程序正常运行结果如下:

原文链接:https://blog.youkuaiyun.com/CTO_51/article/details/8852971

 原文链接:https://blog.youkuaiyun.com/LbinBB/article/details/89231346
原文链接:https://blog.youkuaiyun.com/LbinBB/article/details/89231346

原文链接:https://blog.youkuaiyun.com/vahalla233/article/details/88593443

<think>好的,用户现在问的是构造函数析构函数,需要我来解释这两个概念。首先,我需要确认用户的技术背景。用户之前问过关于算卦的问题,现在转向编程问题,可能是在学习C++或者类似的面向对象编程语言,所以应该用比较基础但清晰的语言来解释。 构造函数析构函数是面向对象编程中的重要概念,特别是在C++中。构造函数用于初始化对象,当对象被创建时自动调用。析构函数则是在对象销毁时自动调用,用于释放资源。用户可能刚开始学习,需要明确它们的定义、作用使用场景。 接下来,我需要考虑用户可能的疑问点。比如,为什么需要构造函数析构函数?它们普通函数有什么区别?有没有例子可以说明它们的使用?另外,用户可能想知道默认构造函数自定义构造函数的区别,以及何时需要显式定义析构函数,比如在涉及动态内存分配时。 我需要用简单明了的例子来辅助解释。例如,构造函数的例子可以是一个类的初始化过程,设置成员变量的初始值。析构函数的例子可以是释放动态分配的内存,避免内存泄漏。同时,应该提到默认情况下编译器会生成默认的构造函数析构函数,但在某些情况下需要自定义。 另外,需要注意用户的潜在需求。用户可能正在准备面试,或者在学习过程中遇到了相关问题,需要清晰的解释来巩固知识。因此,回答要结构清晰,分点说明,并且包含示例代码,这样用户更容易理解。 最后,确保语言口语化,避免使用过于专业的术语,或者在使用时加以解释,让即使初学者也能明白。同时,提醒用户注意资源管理的重要性,特别是在使用析构函数时,防止内存泄漏等问题。</think>好的!构造函数(Constructor)析构函数(Destructor)是面向对象编程(如C++、Java、Python等)中的核心概念,主要用于对象的**初始化****资源清理**。以下是通俗解释: --- ### **1. 构造函数(Constructor)** - **作用**: 在对象**创建时自动调用**,用于初始化对象的成员变量或执行必要的准备工作(如分配内存、连接数据库等)。 - **特点**: - 与类同名,无返回值(连`void`也没有)。 - 可以重载(多个不同参数的构造函数)。 - 如果未显式定义,编译器会生成一个默认的无参构造函数(但若自定义了构造函数,默认的会被覆盖)。 - **示例(C++)**: ```cpp class Student { public: string name; int age; // 构造函数1:无参数 Student() { name = "未知"; age = 0; } // 构造函数2:带参数 Student(string n, int a) { name = n; age = a; } }; // 使用 Student s1; // 调用无参构造函数(name="未知", age=0) Student s2("小明", 18); // 调用带参构造函数 ``` --- ### **2. 析构函数(Destructor)** - **作用**: 在对象**销毁时自动调用**,用于释放对象占用的资源(如关闭文件、释放动态内存等)。 - **特点**: - 类名前加`~`符号,无参数返回值。 - 不可重载(每个类只能有一个析构函数)。 - 如果未显式定义,编译器会生成默认析构函数(但默认的只会释放成员变量,无法释放动态内存等资源)。 - **示例(C++)**: ```cpp class FileHandler { private: FILE* file; public: // 构造函数:打开文件 FileHandler(string filename) { file = fopen(filename.c_str(), "r"); } // 析构函数:关闭文件 ~FileHandler() { if (file != nullptr) { fclose(file); cout << "文件已关闭!" << endl; } } }; // 使用 { FileHandler fh("data.txt"); // 构造函数打开文件 } // 离开作用域时,析构函数自动关闭文件 ``` --- ### **关键对比** | | **构造函数** | **析构函数** | |----------|---------------------------|---------------------------| | **调用时机** | 对象创建时(`new`或声明时) | 对象销毁时(`delete`或作用域结束) | | **主要任务** | 初始化对象 | 清理资源(如内存、文件句柄) | | **默认生成** | 是(若未显式定义) | 是(若未显式定义) | | **重载** | 支持 | 不支持 | --- ### **实际应用场景** - **构造函数**:初始化对象状态(如设置默认值、建立网络连接)。 - **析构函数**:防止资源泄漏(如释放`new`分配的内存、关闭数据库连接)。 - **特殊场景**: - 若类中有动态内存(如`new int[100]`),必须自定义析构函数来释放内存。 - 某些语言(如Java)有垃圾回收机制,析构函数(`finalize()`)较少手动使用。 --- **总结**:构造函数是对象的“出生仪式”,析构函数是“临终善后”,二者共同保障对象的生命周期管理。合理使用它们能大幅提升代码的健壮性! 🛠️
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值