【C++婚恋交友小项目】类与文件初试

一.功能

控制台输入:

杨过 25 15000

郭靖 28 8000

段誉 35 50000

0

小龙女 18 95

如花 25 79

秋香 26 90

李莫愁 26 100

控制台输出: 配对结果
在这里插入图片描述

文件输出:

boys.txt

男 姓名:杨过      年龄:25  月薪:15000
男 姓名:郭靖      年龄:28  月薪:8000
男 姓名:段誉      年龄:35  月薪:50000
男 姓名:larry     年龄:22  月薪:18000
男 姓名:肉肉      年龄:20  月薪:6000
男 姓名:小猪      年龄:15  月薪:10000
男 姓名:小可爱    年龄:20  月薪:20000
男 姓名:aa        年龄:30  月薪:25000
男 姓名:33        年龄:33  月薪:12000
男 姓名:22        年龄:22  月薪:20000
男 姓名:小柔      年龄:40  月薪:20000
男 姓名:最后      年龄:99  月薪:20000

girls.txt

女 姓名:小龙女    年龄:18  颜值:95
女 姓名:如花      年龄:25  颜值:79
女 姓名:秋香      年龄:26  颜值:90
女 姓名:李莫愁    年龄:26  颜值:100
女 姓名:jessica   年龄:20  颜值:99
女 姓名:自已      年龄:22  颜值:99
女 姓名:小熊      年龄:20  颜值:80

二.设计思路

设计类图:
在这里插入图片描述

( 上图为在Visual Studio2019类视图下选中想生成的类图文件, 右键查看类图得到 )

男士提取信息: 姓名, 年龄, 月薪; 女士提取信息: 姓名, 年龄, 颜值

可提供方法: 数据库所有男女配对信息; 控制台输入男士或女士的所有配对或最佳配对用户; 输入男女的所有配对或最佳配对用户.

设计构思: 男士与女士存在共同信息, 故设置虚基类Single单身类, 标识共同的age, name, trait(月薪或年龄). Database数据库用来处理数据, 通过文件保存往期输入数据, 每次启动从文件中读取所有用户数据.

故设计三个方法实现上述功能:

load 加载: 含获取控制台输入(input->vector newGirls)与输出存储至文件(vector newGirls->file) + 读取文件(file->vector allGirls)

match 配对: 输入用户配对( newGirls与allBoys 或 newBoys与allGirls) 所有用户配对( allBoys与allGirls ) 双方满意则算配对成功

bool Girl::satisfied(const Boy& boy)const
{
	return boy.trait() >= faceScore * FACESCORE_COEFFICIENT;
}
bool Boy::satisfied(const Girl& girl)const
{	
	return girl.trait() >= (salary* SALARY_COEFFICIENT > 100 ? 100 : salary * SALARY_COEFFICIENT);
}

bestMatch 最佳配对: 输入用户最佳配对( newGirls与allBoys 或 newBoys与allGirls, 仅选取operator>运算符重载中比较条件最大的用户 ) 所有用户配对( allBoys与allGirls, , 仅选取operator>运算符重载中比较条件最大的用户 ) 本例中为

bool Girl::operator>(const Girl& girl)const
{
	return faceScore > girl.faceScore;
}
bool Boy::operator>(const Boy& boy)const
{
	return salary > boy.salary;
}

( 采取遍历比较, 取得双方满意且最大值, 后续可研究如何最快查找 )

注: 因存在只配对输入用户的情况, 故需区分输入用户与文件中已有用户, 另定义vectornewGirls和vector newBoys

三.实现

Single.h

#pragma once
#include <iostream>
#include <vector>
using namespace std;

class Single {
public:
	Single(string name, int age);

	string getName()const;
	int getAge()const;

	virtual int trait()const = 0;

protected:
	string name;
	int age;
};

Single.cpp

#include "Single.h"
Single::Single(string name = "", int age = 0)
	   : name(name),age(age){}

string Single::getName()const {
	return name;
}
int Single::getAge()const {
	return age;
}

Girl.h

#pragma once
#include <iostream>
#include <vector>
#include "Single.h"
using namespace std;
class Boy;

class Girl:public Single{
public:
	Girl(string name = "", int age = 0, int faceScore = 0);

	int trait()const{
		return faceScore;
	}
	bool satisfied(const Boy& boy)const;
	//string Girl::description()const;
	bool operator>(const Girl& girl)const;
	friend ostream& operator<<(ostream& os, const Girl& girl);

	static void inputGirls(vector<Girl>& girls);

private:
	int faceScore;//颜值
};
ostream& operator<<(ostream& os, const Girl& girl);

Girl.cpp

#include "Girl.h"
#include <sstream>
#include <iomanip>
#define FACESCORE_COEFFICIENT 100
#include "Boy.h"
Girl::Girl(string name, int age, int faceScore) 
	 :Single (name, age), faceScore(faceScore) {}

bool Girl::satisfied(const Boy& boy)const
{
	if ( boy.trait() >= faceScore * FACESCORE_COEFFICIENT) return true;//因为有boy的方法,所以要包括boy的头文件
	return false;
}

bool Girl::operator>(const Girl& girl)const
{
	return faceScore > girl.faceScore;
}

void Girl::inputGirls(vector<Girl>& girls)
{
	int n = 1;
	while (1) {
		string name;
		int age;
		int faceScore;

		cout << "请输入第" << n << "位小姐姐的姓名(输入0结束):";
		cin >> name;//需要另外定义形参,最后一并通过vector名.push_back存入
		if (name == "0") break;
		cout << "年龄:";
		cin >> age;
		cout << "颜值:";
		cin >> faceScore;

		girls.push_back(Girl(name, age, faceScore));//可不通过类型调用带参构造函数

		n++;
	}
}
ostream& operator<<(ostream& os, const Girl& girl) {
	os  << "女 姓名:" << setw(9) << left << girl.name//left=setiosflags(ios::left)
		<< " 年龄:" << setw(4) << girl.age
		<< "颜值:" << girl.faceScore << endl;
	return os;
}

Boy.h

#pragma once
#include <iostream>
#include <vector>
#include "Single.h"
using namespace std;
class Girl;

class Boy:public Single{
public:
	Boy(string name, int age, int salary);

	int trait()const{
		return salary;
	}
	bool satisfied(const Girl& girl)const;
	//string description()const;

	bool operator>(const Boy& boy)const;

	static void inputBoys(vector<Boy>& boys);//控制台中转至容器,容器中转至文件

	friend ostream& operator<<(ostream& os, const Boy& boy);
private:
	int salary;
};
ostream& operator<<(ostream& os, const Boy& boy);

Boy.cpp

#include "Boy.h"
#include <sstream>
#include <iomanip>
#include "Girl.h"
#define SALARY_COEFFICIENT 0.006

Boy::Boy(string name = "", int age = 0, int salary = 0) 
	:Single(name, age),salary(salary) {}//若二者合一,则定义新变量时是否需要带括号??必须带括号,因为不存在默认构造函数!


bool Boy::satisfied(const Girl& girl)const
{	
	int satisfiedFaceScore = salary * SALARY_COEFFICIENT;
	if (salary * SALARY_COEFFICIENT > 100) satisfiedFaceScore = 100;
	if (girl.trait() >= satisfiedFaceScore) return true;
	return false;
}

//string Boy::description()const
//{
//	stringstream ret;
//	ret << "男 姓名:" << setw(9) << left << name 
//		<< " 年龄:" << setw(4) << age 
//		<< "月薪:" << salary;//流向ret;cout<<xxx,为将xxx流向控制台输出
//	return ret.str();
//}

bool Boy::operator>(const Boy& boy)const
{
	return salary > boy.salary;
}

void Boy::inputBoys(vector<Boy>& boys)
{
	int n = 1;
	while (1) {
		string name;
		int age;
		int salary;

		cout << "请输入第" << n << "位小哥哥的姓名(输入0结束):";
		cin >> name;//需要另外定义形参,最后一并通过vector名.push_back存入,push_back意为推到最后面,每次加入的都位于最后,像排队一样
		if (name == "0") break;
		cout << "年龄:";
		cin >> age;
		cout << "月薪:";
		cin >> salary;

		boys.push_back(Boy(name, age, salary));//可不通过类型调用带参构造函数
		n++;
	}
}
//cout << 重载和比较 < 重载
ostream& operator<<(ostream& os, const Boy& boy) {//直接打印,无需返回stringstream.str()的函数中转
	os << "男 姓名:" << setw(9) << left << boy.name
		<< " 年龄:" << setw(4) << boy.age
		<< "月薪:" << boy.salary << endl;
	return os;
}

由description升级为operator<<打印基本信息

Database.h

#pragma once
#include "Boy.h"
#include "Girl.h"

/*
功能:
加载用户信息load()
实现自动配对automatch()
打印配对信息print()
数据:
男信息
女信息
*/

class Database
{
public:
	Database();

	void load(bool input = false) {
		loadBoys(input);
		loadGirls(input);
	}
	void print() const;//打印boys和allGirls中所有男女信息
	void allMatch() const;
	void inputMatch() const;
	void allBestMatch() const;
	void inputBestMatch() const;
private:
	vector<Boy> boys;//vector每次用之前需要初始化为0吗?
	vector<Girl>allGirls;
	vector<Boy> newBoys;
	vector<Girl> newGirls;

	void loadBoys(bool input);//将文件中加载至vector
	void loadGirls(bool input);

	void saveBoys(const vector<Boy>& boys);//将vector中存入文件
	void saveGirls(const vector<Girl>&allGirls);

	void automatchBoy(const vector<Boy>& boys, const vector<Girl>&allGirls) const;
	void automatchGirl(const vector<Boy>& boys, const vector<Girl>&allGirls) const;

	void bestMatchBoy(const vector<Boy>& boys, const vector<Girl>&allGirls) const;
	void bestMatchGirl(const vector<Boy>& boys, const vector<Girl>&allGirls) const;
};

Database.cpp

#include <fstream>
#include <string>
#include "Database.h"
#define BOY_FILE "boys.txt"
#define GIRL_FILE "girls.txt"
#define BOY_INPUT_INFO 3	//男士输入数据数目(姓名,年龄,月薪)
#define GIRL_INPUT_INFO 3	//女士输入数据数目(姓名,年龄,颜值)
string line(100, '-');

Database::Database()
{
}
void Database::allMatch() const {
	cout << line << endl;
	cout << "全部单身男女自动配对结果:" << endl;
	automatchBoy(boys, allGirls);
	cout << line << endl;
	automatchGirl(boys, allGirls);
	cout << line << endl;
}
void Database::inputMatch() const {
	cout << line << endl;
	cout << "输入单身男自动配对结果:" << endl;
	automatchBoy(newBoys, allGirls);
	cout << line << endl;
	cout << "输入单身女自动配对结果:" << endl;
	automatchGirl(boys, newGirls);
	cout << line << endl;
}
void Database::allBestMatch() const
{
	cout << line << endl;
	cout << "全部单身男女最佳配对结果:" << endl;
	bestMatchBoy(boys, allGirls);
	cout << line << endl;
	bestMatchGirl(boys, allGirls);
	cout << line << endl;
}

void Database::inputBestMatch() const
{
	cout << line << endl;
	if (newBoys.size())
	{
		cout << "输入单身男最佳配对结果:" << endl;
		bestMatchBoy(newBoys, allGirls);
		cout << line << endl;
	}

	if (newGirls.size())
	{
		cout << "输入单身女最佳配对结果:" << endl;
		bestMatchGirl(boys, newGirls);
		cout << line << endl;
	}	
}

void Database::bestMatchBoy(const vector<Boy>& boys, const vector<Girl>& allGirls) const {
	for (unsigned int b = 0; b < boys.size(); b++) {
		cout << boys[b] << " 的最佳配对女士为:" << endl;
		const Girl* bestGirl = NULL;
		for (unsigned int g = 0; g < allGirls.size(); g++) {
			if (boys[b].satisfied(allGirls[g]) == true &&
				allGirls[g].satisfied(boys[b]) == true) {//注意调用的是否是函数以及函数是否含参以及含参顺序
				//cout << boys[b].getName() << "<-->" << allGirls[g].getName() << endl;如果只打印姓名,可能有重名,无法确定实际是哪位
				//因为database与Boy和Girl类不存在继承关系,所以只能通过对象调用public方法
				if (!bestGirl) {
					bestGirl = &allGirls[g];
				}
				else if (allGirls[g] > *bestGirl) {
					bestGirl = &allGirls[g];
				}
			}
		}
		if (bestGirl) {
			cout << *bestGirl;
		}
		else {
			cout << "配对失败!" << endl;
		}
		cout << endl;//一位男士的所有配对结束后空一行
	}
}
void Database::bestMatchGirl(const vector<Boy>& boys, const vector<Girl>& allGirls) const {
	for (unsigned int g = 0; g < allGirls.size(); g++) {
		cout << allGirls[g] << " 的最佳配对男士为:" << endl;
		const Boy* bestBoy = NULL;
		for (unsigned int b = 0; b < boys.size(); b++) {
			if (boys[b].satisfied(allGirls[g]) == true &&
				allGirls[g].satisfied(boys[b]) == true) {//注意调用的是否是函数以及函数是否含参以及含参顺序
				//cout << boys[b].getName() << "<-->" << allGirls[g].getName() << endl;如果只打印姓名,可能有重名,无法确定实际是哪位
				//因为database与Boy和Girl类不存在继承关系,所以只能通过对象调用public方法
				if (!bestBoy) {
					bestBoy = &boys[b];
				}
				else if (boys[b] > * bestBoy) {//TO DO <运算符重载
					bestBoy = &boys[b];
				}
			}
		}
		if (bestBoy) {
			cout << *bestBoy;
		}
		else {
			cout << "配对失败!" << endl;
		}
		cout << endl;//一位女士的所有配对结束后空一行
	}
}

void Database::automatchBoy(const vector<Boy>& boys, const vector<Girl>& allGirls)const
{
	//遍历两两配对
	for (unsigned int b = 0; b < boys.size(); b++) {
		cout << boys[b] << " 的配对女士有:" << endl;
		for (unsigned int g = 0; g < allGirls.size(); g++) {
			if (boys[b].satisfied(allGirls[g]) 
				&& allGirls[g].satisfied(boys[b]) ) {//注意调用的是否是函数以及函数是否含参以及含参顺序
				//cout << boys[b].getName() << "<-->" << allGirls[g].getName() << endl;如果只打印姓名,可能有重名,无法确定实际是哪位
				//因为database与Boy和Girl类不存在继承关系,所以只能通过对象调用public方法
				cout << allGirls[g] ;
			}
		}
		cout << endl;//一位男士的所有配对结束后空一行
	}
}
void Database::automatchGirl(const vector<Boy>& boys, const vector<Girl>& allGirls)const
{
	//遍历两两配对
	for (unsigned int g = 0; g < allGirls.size(); g++) {
		cout << allGirls[g] <<" 的配对男士有:"<< endl;
		for (unsigned int b = 0; b < boys.size(); b++) {
			if (boys[b].satisfied(allGirls[g]) 
				&& allGirls[g].satisfied(boys[b]) ) {//注意调用的是否是函数以及函数是否含参以及含参顺序
				//cout << boys[b].getName() << "<-->" << allGirls[g].getName() << endl;如果只打印姓名,可能有重名,无法确定实际是哪位
				//因为database与Boy和Girl类不存在继承关系,所以只能通过对象调用public方法
				cout << boys[b];
			}
		}
		cout << endl;//一位成女士的所有配对结束后空一行
	}
}
void Database::print()const
{
	string line(100, '-');//记得在初始化时这样写

	cout << "男士信息:" << endl;
	for (unsigned int i = 0; i < boys.size(); i++) {
		cout << boys[i];
	}

	cout << "女士信息:" << endl;
	for (unsigned int i = 0; i < allGirls.size(); i++) {
		cout << allGirls[i];
	}

	cout << line << endl;
}

void Database::loadBoys(bool input)
{
	//打开读文件
	ifstream boyfile;
	boyfile.open(BOY_FILE);
	if (!boyfile.is_open()) {
		//还没有此文件名的文件,需要用户输入,作为基础信息,存入vector->vector.vector中已有,不需要再从文件中读取
		Boy::inputBoys(this->newBoys);

		//将vector中的基础信息以description中的格式写入新建的文件,并结束加载
		saveBoys(newBoys);
		boyfile.close();
		return;
	}
	if (input) {
		Boy::inputBoys(this->newBoys);
		saveBoys(newBoys);
	}
	while (1) {

		//将读文件信息解析??为啥要解析嘞??已经存好了的啊,,是为了显示出来吗,要显示出来可以直接按存入的vector显示吗?不能
		//因为vector掉电即失,需写入文件中转
		//sscanf读取字符串会自动跳过回车符
		//根据写的格式读取文件
		/*ret << "男 姓名:" << setw(9) << left << name
			<< " 年龄:" << setw(4) << age
			<< "月薪:" << salary << endl;*/
		string line;
		getline(boyfile, line);
		if (boyfile.eof()) {
			break;
		}

		char name[32]="";
		int age, salary;
		int ret = sscanf_s(line.c_str(), "男 姓名:%s 年龄:%d 月薪:%d", name, sizeof(name), &age, &salary);
		if (ret < BOY_INPUT_INFO) {
			cerr << "男士信息写入有误!" << endl;
			exit(1);//视项目需求:break/exit
		}

		//并加载至vector以供后续配对
		boys.push_back(Boy(name, age, salary));//string存入时最后记得加\0结束符,因为读取的时候要用char型读取,可以不加,因为格式里面专门加了空格隔开

	}
	boyfile.close();

}
//inputGirls:控制台->vector
//saveGirls:vector->文件
void Database::loadGirls(bool input)
{
	ifstream girlfile;
	girlfile.open(GIRL_FILE);

	// 还没有此文件,需要用户输入基础信息
	if ( !girlfile.is_open() ) {
		Girl::inputGirls(this->newGirls);
		//将输入的基础信息以description中的格式保存至文件尾部
		saveGirls(newGirls);
		girlfile.close();
		return;
	}
	// 用户希望输入新信息
	if (input) {
		Girl::inputGirls(this->newGirls);
		//将输入的基础信息以description中的格式保存至文件尾部
		saveGirls(newGirls);
	}

	while (1) {

		//将读文件信息解析??为啥要解析嘞??已经存好了的啊,,是为了显示出来吗,要显示出来可以直接按存入的vector显示吗?不能
		//因为vector掉电即失,需写入文件中转
		//sscanf读取字符串会自动跳过回车符
		//根据写的格式读取文件
		/*	ret << "女 姓名:" << setw(9) << left << name
				<< " 年龄:" << setw(4) << age
				<< "颜值:" << faceScore << endl;*/
		string line;
		getline(girlfile, line);
		if (girlfile.eof()) {
			break;
		}

		char name[32]="";
		int age, faceScore;
		int ret = sscanf_s(line.c_str(), "女 姓名:%s 年龄:%d 颜值:%d", name, sizeof(name), &age, &faceScore);
		if (ret < GIRL_INPUT_INFO) {
			cerr << "女士信息写入有误!" << endl;
			exit(1);//视项目需求:break/exit
		}

		//并加载至vector以供后续配对
		allGirls.push_back(Girl(name, age, faceScore));//string存入时最后记得加\0结束符,因为读取的时候要用char型读取,可以不加,因为格式里面专门加了空格隔开

	}
	girlfile.close();

}

void Database::saveBoys(const vector<Boy>& boys)
{
	ofstream boyfile;
	boyfile.open(BOY_FILE, ios::app);//尾部附加
	if (!boyfile.is_open()) {
		cerr << "写入:男士文件打开失败!" << endl;
		exit(1);//exit还是break按项目需求
	}

	for (unsigned int i = 0; i < boys.size(); i++) {
		boyfile << boys[i];
	}

	boyfile.close();
}

void Database::saveGirls(const vector<Girl>& allGirls)
{
	ofstream girlfile;
	girlfile.open(GIRL_FILE, ios::app);
	if (!girlfile.is_open()) {
		cerr << "写入:女士文件打开失败!" << endl;
		exit(-1);
	}

	for (unsigned int i = 0; i < allGirls.size(); i++) {
		girlfile << allGirls[i];
	}

	girlfile.close();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值