C++类--考试题(检测类的基础实现)

题目说明
LRC 文件是一种基于纯文本的歌词专用格式文档,可以为MP3播放器和播放软件的显示歌词功能提供规范数据。本次考试的程序用于将一个手工编制的歌词信息转化为标准的LRC文件。
请各位考生从课程信息发布网站下载数据文件in.txt,然后将该数据文件手动保存在D盘根目录下。该文件是一个歌词的原始数据文件,数据以文本形式存储,每行包含4列数据,格式如下:A列为分钟,B列是秒,C列是毫秒,D列是歌词,列之间用空格隔开,D列中没有空格和tab符号。下面显示了一个局部样例:
A B C D
0 0 0 张学友-情网
0 17 0 请你再为我点上一盏烛光,
0 62 0 时间错误的歌词
0 25 0 因为我早已迷失了方向,
0 33 0 我掩饰不住的慌张,
0 36 0 在迫不急待地张望,
0 41 0 生怕这一路是好梦一场。
0 48 0 而你是一张无边无际的网,
现有歌词类CLyric,用于存储时间和歌词,该类的数据成员定义如下:
class CLyric
{
private:
int m_Minute; //分钟
int m_Second; //秒
int m_Millisecond; //毫秒
string m_Sentence; //一句歌词
int m_SequenceId; //从1开始的流水序号,每个对象不重复
};
请按要求依次完成如下操作:
1、为CLyric类添加一个携带四个参数的构造函数,前三个参数分别用于初始化分钟、秒和毫秒,第四个参数用于初始化歌词。
注意:
如果前三个参数有一个取值不合法,那么时间相关的三个数据成员全部初始化为0。分钟、秒的取值范围为[0,59],毫秒的取值范围[0,999]。
流水序号的初始化和构造函数参数无关,在构造函数中需要保证对象的流水序号是自动增长的,每次新产生的对象的流水序号比之前用过的最大流水序号大1。可以添加静态数据成员m_MaxId协助完成该需求。
2、为CLyric类添加一个拷贝构造函数实现对象复制,注意:流水序号不能直接复制。
3、为CLyric类添加五个成员函数getMinute、getSecond、getMillisecond、getSentence和,getSequenceId分别用于获取(返回)分钟、秒、毫秒、歌词和流水序号值。
4、为CLyric类重载流输出运算符,用于显示一条歌词信息,格式如下
[MM:SS.PPP] 歌词文本
时间用一对英文方括号括起来,中间的分割冒号和点都是英文字符,其中前两个成员占两位,毫秒占三位,不足前面用0填充,时间和歌词文本之间用一个空格分割。
5、为CLyric类重载后自增运算符用于将秒值加1。注意:先增加秒值,如果超过59,秒值清零,分钟加1;如果分钟值超过59,分钟值清零;毫秒保持不变。
6、为CLyric类重载加上int数据的加号运算符,所加的整数是毫秒数。注意:该整数为非负数,可能大于1000,同样需要处理进位的问题。

7、编写函数readSong,用于实现把D盘的in.txt中的数据读取到向量song中保存,读取时需要舍弃异常的数据(分钟、秒或者毫秒取值不合法),并返回异常数据的行数。
8、编写函数showTopN用于把向量song中的前n条歌词数据显示在屏幕上,每条歌词显示格式和第4步格式相同。注意:当向量中数据不足n条时显示向量的全部数据。
9、编写函数offsetSong,用于实现把向量song中所有的歌词的时间后移1秒。
10、编写CLyric类的友元函数writeSong用于将向量song中的全部数据存储到D盘的文本文件out.lrc中,存储格式和第4步格式相同,每条歌词单独一行。
11、main函数如下://不可更改
int main()
{
CLyric time1(61,12,125,“考试之歌”);
cout << “输出time1:” << endl;
cout << “id=” << time1.getSequenceId() << " " << time1 << endl;
CLyric time2(59, 59, 500,“双截棍”);
cout << “执行加号运算符后time2:” << endl;
time2 = time2 + 2000;
cout <<“id=”<<time2.getSequenceId()<<" "<<time2 << endl;
cout << “执行后置++运算符后time2:” << endl;
time1 = time2++;
cout << “id=” << time2.getSequenceId() << " " << time2 << endl;

vector<CLyric> song;
cout << "读取原始歌词文件" << endl;
int count=readSong("d:\\in.txt", song);
cout << "共有" << count << "行不合法数据" << endl;

cout << "歌词前5行是:" << endl;
showTopN(song, 5);
offsetSong(song);
cout << "正在生成歌词文件......"<<endl;
writeSong("d:\\out.lrc", song);
cout << "生成歌词文件成功!"<<endl;
return 0;

}

文档数据

源码如下

*表示需注意的地方

#include<iostream>
#include<sstream>
#include<iomanip>
#include<string>
#include<fstream>
#include<vector>
using namespace std;

class CLyric
{
private:
	static int m_MaxId;
	int 	m_Minute;			//分钟
	int 	m_Second;			//秒
	int 	m_Millisecond; 	//毫秒
	string m_Sentence;		//一句歌词
	int	  	m_SequenceId;		//从1开始的流水序号,每个对象不重复
public:
	CLyric(int Minute, int Second, int Millisecond, string Sentence);
	CLyric(const CLyric& obj);//***************
	int getMinute() { return m_Minute; }
	int getSecond() { return m_Second; }
	int getMillisecond() { return m_Millisecond; }
	string getSentence() { return m_Sentence; }
	int getSequenceId() { return m_SequenceId; }
	friend ostream& operator<<(ostream& out, const CLyric& obj);//一般<<用友元和函数引用返回***************************************
	friend CLyric operator++(CLyric& a, int);
	friend CLyric operator+(const CLyric& a, int num);
	friend void writeSong( const string& filename, const vector<string>& song);
};

int CLyric::m_MaxId = 0;//记住类外定义*********************************

CLyric::CLyric(int Minute, int Second, int Millisecond, string Sentence)
{
	if (Minute > 59 || Minute < 0 || Second>59 || Second < 0 || Millisecond>999 || Millisecond < 0)
	{
		m_Minute = 0; m_Second = 0; m_Millisecond = 0; m_MaxId++; m_SequenceId = m_MaxId;
		m_Sentence = Sentence;
	}
	else
	{
		m_Sentence = Sentence;
		m_Minute = Minute; m_Second = Second; m_Millisecond = Millisecond; m_MaxId++; m_SequenceId = m_MaxId;
	}
}

ostream& operator<<(ostream& out, const CLyric& obj)
{
	out << "[" << setfill('0') << right << setw(2) << obj.m_Minute << ":"
		<< setfill('0') << right << setw(2) << obj.m_Second << "."
		<< setfill('0') << right << setw(3) << obj.m_Millisecond
		<< "] " << obj.m_Sentence;
	return out;
}

CLyric::CLyric(const CLyric& obj)
{
	m_Minute = obj.m_Minute;
	m_Second = obj.m_Second;
	m_Millisecond = obj.m_Millisecond;
	m_Sentence = obj.m_Sentence;
	m_MaxId++;
	m_SequenceId = m_MaxId;
}

CLyric operator++(CLyric& a, int)
{
	CLyric temp(a);
	a.m_Second++;
	if (a.m_Second == 60)
	{
		a.m_Minute++;
		a.m_Second = 0;
		if (a.m_Minute == 60)
		{
			a.m_Minute = 0;
		}
	}
	return temp;
}

CLyric operator+(const CLyric& a, int num)
{
	CLyric temp(a);
	temp.m_Millisecond += num;
	if (temp.m_Millisecond > 999)
	{
		temp.m_Second+=int(temp.m_Millisecond/1000);
		temp.m_Millisecond = temp.m_Millisecond % 1000;
		if (temp.m_Second > 59)
		{
			temp.m_Minute += int(temp.m_Second / 60);
			temp.m_Second = temp.m_Second % 60;
			if (temp.m_Minute > 59) temp.m_Minute = temp.m_Minute % 60;
		}
	}
	return temp;
}

int readSong(const string &filname, vector<CLyric>& song)
{
	int sum = 0;
	ifstream fin(filname);//记住读是ifstream****************************
	if (fin.good())
	{
		int minute, second, mill;
		string sen;
		while (fin >> minute >> second >> mill >> sen)
		{
			if (minute > 59 || minute < 0 || second>59 || second < 0 || mill>999 || mill < 0)
			{
				sum++;
			}
			else
			{
				CLyric temp(minute, second, mill, sen);
				song.push_back(temp);
			}
		}
		fin.close();
		return sum;
	}
	else
	{
		cout << "open file error";
	}
}

void showTopN(const vector<CLyric> song, int num)
{
	if (song.size() < num)
	{
		num = song.size();
	}
	for (int i = 0; i < num; i++)
	{
		cout << song[i] << endl;
	}
}

void writeSong(const string& filename,const vector<CLyric>& song)
{
	ofstream fout(filename);//记住写入是ofstream****************************
	if (fout.good())
	{
		for (int i = 0; i < song.size();i++)
		{
			fout << song[i] << endl;
		}
		fout.close();
	}
	else
	{
		cout << "open error";
		exit(0);
	}
}

void offsetSong(vector<CLyric>& song)
{
	for (int i = 0; i < song.size(); i++)
	{
		song[i]++;//记住进行自增调用之前类的函数***********
	}
}

int main()
{
	CLyric time1(61, 12, 125, "考试之歌");
	cout << "输出time1:" << endl;
	cout << "id=" << time1.getSequenceId() << " " << time1 << endl;
	CLyric time2(59, 59, 500, "双截棍");
	cout << "执行加号运算符后time2:" << endl;
	time2 = time2 + 2000;
	cout << "id=" << time2.getSequenceId() << " " << time2 << endl;
	cout << "执行后置++运算符后time2:" << endl;
	time1 = time2++;
	cout << "id=" << time2.getSequenceId() << " " << time2 << endl;

	vector<CLyric> song;
	cout << "读取原始歌词文件" << endl;
	int count = readSong("d:\\in.txt", song);
	cout << "共有" << count << "行不合法数据" << endl;

	cout << "歌词前5行是:" << endl;
	showTopN(song, 5);
	offsetSong(song);
	cout << "正在生成歌词文件......" << endl;
	writeSong("d:\\out.lrc", song);
	cout << "生成歌词文件成功!" << endl;
	return 0;
}

结果截图
在这里插入图片描述

ps:博主发此博文来记录自己曾踩过的坑。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Rikka_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值