宠物的生长(虚函数和多态)
题目描述:
需要开发一个系统,对宠物的生长状态进行管理。给出下面的基类框架:
class Pet
{ protected:
string name;//姓名
float length;//身长
float weight;//体重
CDate current;//开始记录时间
(日期类CDate包含年、月、日三个私有数据,其他方法根据需要自拟。)
public:
virtual void display(CDate day)=0;//输出目标日期时宠物的身长和体重
}
以Pet为基类,构建出Cat和Dog两个类:
Cat一天身长加0.1,体重加0.2。
Dog一天身长加0.2,体重加0.1。
生成上述类并编写主函数,要求主函数中有一个基类指针Pet *pt,用于测试子类数据。
主函数根据输入的信息,相应建立Cat类对象或Dog类对象,并给出测量日期时宠物的身长和体重。
输入:
第一行为测试次数
第二行是开始记录日期
从第三行起,每个测试用例占一行,每行给出宠物的基本信息:宠物的类型(1为Cat,2为Dog)、名字、身长、体重、最后测量的日期。
输出:
要求输出目标日期宠物姓名、身长和体重(结果要求保留小数点后2位)。若测量日期小于开始日期,输出”error”。
输入样例:
3
2019 5 5
1 tony 10 10 2018 12 30
2 jerry 5 6 2019 5 10
1 tom 3 4 2019 6 1
输出样例:
error
jerry after 5 day: length=6.00,weight=6.50
tom after 27 day: length=5.70,weight=9.40
代码(完善):
#include <iostream>
#include <iomanip>
using namespace std;
class CDate {
public:
CDate() {}
CDate(int a, int b, int c) :year(a), month(b), day(c) {}
bool isleapyear() {
return (year % 4 == 0 && year % 100 != 0) || (year % 400) == 0;
}
int getyear(int x, int y) {
int sum = 0;
for (int i = x; i < y; i++) {
CDate c(i, 1, 1);
if (c.isleapyear()) {
sum += 366;
}
else {
sum += 365;
}
}
return sum;
}
friend int getdayofyear(CDate& p);
friend int days(const CDate& a, const CDate& b);
friend int remainday(CDate& q, CDate& p);
private:
int year;
int month;
int day;
};
int getdayofyear(CDate& p) {
int i;
int sum = p.day;
int a[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (p.isleapyear()) {
a[2]++;
}
for (i = 0; i < p.month; i++) {
sum += a[i];
}
return sum;
}
int days(const CDate& a, const CDate& b) {
return a.year * 10000 + a.month * 100 + a.day < b.year * 10000 + b.month * 100 + b.day;
}
int remainday(CDate& q, CDate& p) {
int sum;
sum = q.getyear(q.year, p.year) - getdayofyear(q) + getdayofyear(p);
return sum;
}
class Pet {
protected:
string name;
float length;
float weight;
CDate current;
public:
Pet() {}
Pet(string na, float le, float we, CDate current) :current(current) {
name = na;
length = le;
weight = we;
}
virtual void display(CDate day) = 0;
};
class Cat :public Pet {
public:
Cat(string na, float le, float we, CDate current) :Pet(na, le, we, current) {}
virtual void display(CDate day) {
if (days(current, day) == 0) {
cout << "error" << endl;
}
else {
int re = remainday(current, day);
length += 0.1 * re;
weight += 0.2 * re;
cout << name << " after " << re << " day: length=" << fixed << setprecision(2) << length << ",weight=" << fixed << setprecision(2) << weight << endl;
}
}
};
class Dog :public Pet {
public:
Dog(string na, float le, float we, CDate current) :Pet(na, le, we, current) {}
virtual void display(CDate day) {
if (days(current, day) == 0) {
cout << "error" << endl;
}
else {
int re = remainday(current, day);
length += 0.2 * re;
weight += 0.1 * re;
cout << name << " after " << re << " day: length=" << fixed << setprecision(2) << length << ",weight=" << fixed << setprecision(2) << weight << endl;
}
}
};
int main()
{
int t;
int year1, month1, day1;
int year2, month2, day2;
int type;
float length, weight;
Pet* pt = NULL;
string name;
cin >> t;
cin >> year1 >> month1 >> day1;
CDate date1(year1, month1, day1);
while (t--) {
cin >> type;
cin >> name >> length >> weight;
cin >> year2 >> month2 >> day2;
CDate date2(year2, month2, day2);
if (type == 1) {
pt = new Cat(name, length, weight, date1);
}
else if (type == 2) {
pt = new Dog(name, length, weight, date1);
}
pt->display(date2);
}
}
我的总结:
1、日期的计算:
通常题目要求的是计算一个日期到另一个日期的天数,如到保质期的天数,两人生日相差的距离等等,是期中考试和期末考试的常考点。
刚开始的时候我的代码思路为:1)如果不同年,先计算第一个人(年龄大的)的生日到年末的天数,再计算两人相差的年数的天数,最后计算第二个人年初到他生日的天数,相加即可。2)同年的再次不再进行讨论。
编写的代码为:
friend int remainday(CDate &q, CDate& p) {
int sum = 0;
if (q.year != p.year) {
int a[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
sum += a[q.month] - 5;
for (int i = q.month + 1; i <= 12; i++) {
sum += a[i];
}
for (int i = q.year; i < p.year; i++) {
CDate c(i, 1, 1);
if (c.isleapyear()) { sum += 366; }
else {
sum += 365;
}
}
if (q.isleapyear()) {
a[2] = 29;
}
for (int i = 1; i < p.month; i++) {
sum += a[i];
}
sum += p.day;
}
else {
int a[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (q.isleapyear()) {
a[2] = 29;
}
if (q.month != p.month) {
for (int i = q.month+1; i < p.month; i++) {
sum += a[i];
}
sum += a[q.month] - q.day;
sum += p.day;
}
else {
sum += p.day - q.day;
}
}
return sum;
}
可以看出,代码的编写非常的长,可读性较差,不太符合代码的编写规范。
通过参考一些资料,我找到了可读性较好的代码。
具体的思路为:1)定义一个函数,如getdayofyear( )来计算一年的年初到每个日期的天数。2)再定义一个函数,如getyear( )来计算两个日期所隔的年数的天数。(第二个日期所在的年数之前的年数)3)再定义一个函数,如remainday( )利用以上所定义的函数来计算两个日期所隔的天数。
所必须的代码如下:
//以下函数均为在类内所定义的
//判断是否为闰年的函数
bool isleapyear() {
return (year % 4 == 0 && year % 100 != 0) || (year % 400) == 0;
}
//计算一年的年初到每个日期的天数的函数(运用友元函数)
friend int getdayofyear(CDate& p) { //参数为一个所需计算的类
int i;
int sum = p.day;
int a[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (p.isleapyear()) {
a[2]++;
}
for (i = 0; i < p.month; i++) {
sum += a[i];
}
return sum;
}
//计算两个日期所隔的年数的天数的函数(第二个日期所在的年数之前的年数)
int getyear(int x, int y) { //参数为两个日期
int sum = 0;
for (int i = x; i < y; i++) {
CDate c(i, 1, 1);
if (c.isleapyear()) {
sum += 366;
}
else {
sum += 365;
}
}
return sum;
}
//来计算两个日期所隔的天数的函数(主要函数)
int remainday(CDate& q, CDate& p) { //参数为两个所需计算所隔日期的类
int sum;
sum = q.getyear(q.year, p.year) - getdayofyear(q) + getdayofyear(p);
return sum;
}
//比较函数(可能需要)
bool days(const CDate& a, const CDate& b) {
return a.year * 10000 + a.month * 100 + a.day > b.year * 10000 + b.month * 100 + b.day;
}
可以看出,这样编写的代码思路清晰,可读性较好。
2、继承与虚继承:
1)“主函数中有一个基类指针Pet *pt,用于测试子类数据”:
代码如下:
int main()
{
...
Pet* pt = NULL;
if (type == 1) {
pt = new Cat(name, length, weight, date1);
}
else if (type == 2) {
pt = new Dog(name, length, weight, date1);
}
pt->display(date2);
...
}
注意点:在if作用域中,一定要new生成新类来调用构造函数,因为如果不用new生成时,该作用域结束后,生成的类对象会消亡,将无法经行display操作
2)虚函数:
class Pet{
public:
virtual void display(CDate day)=0;//输出目标日期时宠物的身长和体重 不进行实现!
...
}
class Cat :public Pet{
public:
virtual void display(CDate day) {
if (days(current, day) == 0) {
cout << "error" << endl;
}
else {
int re = remainday(current, day);
length += 0.1 * re;
weight += 0.2 * re;
cout << name << " after " << re << " day: length=" << fixed << setprecision(2) << length << ",weight=" << fixed << setprecision(2) << weight << endl;
}
}
...
}
class Dog :public Pet {
public:
virtual void display(CDate day) {
if (days(current, day) == 0) {
cout << "error" << endl;
}
else {
int re = remainday(current, day);
length += 0.2 * re;
weight += 0.1 * re;
cout << name << " after " << re << " day: length=" << fixed << setprecision(2) << length << ",weight=" << fixed << setprecision(2) << weight << endl;
}
}
...
}