一.功能
控制台输入:
杨过 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();
}