实验四 对象作为数据成员
1 实验目的
学习对象作为类的数据成员的使用方法,学习对象数据成员的初始化以及“成员初始化器”的使用方法。
2 实验内容
2.1 使用 Date 类,定义 Employee 类
(1)问题描述
在《实验三 面向对象初步》中,设计了日期类 Date。本次实验将设计雇员类 Employee,并将日期类 Date 作为雇员类 Employee 的内嵌数据成员。日期类
Date 和雇员类 Employee 的声明分别如下所示:
class Date {
public:
/* 默认构造函数,以fullyear的形式给出年月日,默认值为1990年1月1日,同时设置日
期分隔符为“-” */
Date(int year = 1990, int month = 1, int day = 1);
/* get、set方法 */
// 设置日期,如果有非法的月或日,将其置为1
void setDate(int year, int month, int day);
void setYear(int year);
int getYear();
void setMonth(int month);
int getMonth();
void setDay(int month);
int getDay();
void setSeparator(char separator);
/* 输出函数,请使用setfill(‘0’)和setw(2)。*/
void printFullYear(); //以YYYY-MM-DD的形式打印,2011-01-08
void printStandardYear(); //以YY-MM-DD的形式打印,比如11-01-08
/* 计算当前日期与参数日期之间相差几个整年,仅考虑参数日期比当前日期晚的情况。
注意参数为日期对象的引用。*/
int fullYearsTo(Date &date);
/* 计算当前日期与参数日期之间相差多少天(考虑闰年),如果参数日期在当前日期之前,
返回负数。注意参数为日期对象的引用。*/
int daysTo(Date &date);
/* 新增函数,可以被daysTo函数调用 */
int getDayOfYear(); //计算当前日期是本年的第几天
int getLeftDaysYear(); //计算当前日期距本年结束还有几天,不包括当前日期这一
天
private:
int year;
int month;
int day;
char separator; // 日期分隔符
/* 新增数据成员和函数成员 */
/*声明静态常变量,每月的天数,在.cpp文件中定义并初始化 */
static int DAYS_PER_MONTH[12];
/*根据年和月,判断参数日期是否合法。如果合法,返回day,否则返回1。*/
int checkDay(int day);
bool isLeapyear(int year);//断参数年是否是闰年。
};
class Employee{
public:
//构造函数,使用“成员初始化器”初始化数据成员
Employee(string, string, Date &, Date &);
//打印员工的信息。调用Date类的print函数,打印员工的生日和雇佣日期。
void print();
//计算员工在参数指定的日期时,满多少岁。请使用Date类的fullYearsTo函数
int getAge(Date &date);
//计算该员工在参数指定的日期时,工作满了多少年。
int getYearsWorked(Date &date);
//计算该员工在参数指定的日期时,工作了多少天。使用Date类的daysTo函数。
int getDaysWorked(Date &date);
~Employee(); //析构函数
private:
string firstName;
string lastName;
Date birthDate; //内嵌对象,出生日期
Date hireDate; //内嵌对象,雇用日期
};
(2)问题要求
可以满足以下主函数的要求:
#include <iostream>
#include <string>
using namespace std;
void main() {
Date birth(1969, 8, 11);
Date hire(1998, 4, 1);
Date today(2010, 4, 30);
Employee manager("Bob", "Blue", birth, hire);
cout << endl;
manager.print();
cout << endl;
cout << manager.getAge(today) << endl;
cout << manager.getDaysWorked(today) << endl;
}
输出结果如下,其中的注释仅为了说明运行结果,实际执行时不必输出。
//调用manager.print()后,打印以下信息
Blue, Bob Hired: 1998-04-01 Birthday: 1969-08-11
//调用manager.getAge(today)后,打印以下信息
40 // 工作满了40年
//调用manager.getDaysWorked(today)
4412 // 已工作了4412天 3
4
源代码
Date.cpp
#include <iostream>
#include <iomanip>
#include "Date.h"
using namespace std;
// constructor confirms proper value for month; calls utility function checkDay to confirm proper value for day
Date::Date(int year, int month, int day) {
setYear(year);
setMonth(month);
setDay(day);
setSeparator('-');
}
void Date::setYear(int year) {
this->year = year;
}
void Date::setMonth(int month) {
if (month >= 0 && month <= 12)
this->month = month;
else {
this->month = 1;
cout << "Invalid month (" << month << ") set to 1.\n";
}
}
void Date::setDay(int day) {
this->day = checkDay(day); // validate the day.
}
void Date::setSeparator(char c) {
separator = c;
}
int Date::getYear() const {
return year;
}
int Date::getMonth() const {
return month;
}
int Date::getDay() const {
return day;
}
char Date::getSeparator() const {
return separator;
}
//Print Date object in form YYYY-MM-DD
void Date::printFullYear() const {
cout << year << separator
<< setfill('0') << setw(2) << month << separator
<< setw(2) << day;
}
//Print Date object in form YY-MM-DD
void Date::printStandardYear() const {
cout << setfill('0') << setw(2) << (year % 100) << separator
<< setw(2) << month << separator
<< setw(2) << day;
}
// 计算当前日期与参数日期之间相差几个整年,注意参数为日期对象的引用
int Date::fullYearsTo(const Date &date) const {
// 如果当前日期的月小于参数日期的月;
// 或者月相等,并且当前日期的日小于等于参数日期的日
if ((month < date.month) || (month == date.month && day <= date.day))
return date.year - year;
else
return date.year - year - 1;
}
// 计算当前日期比参数日期晚了多少天(考虑闰年)
// 如果参数日期晚于当前日期,返回负数,注意参数为日期对象的引用。
int Date::operator -(const Date &date) const {
const Date* startDate; // 开始日期;
const Date* endDate; // 结束日期;
bool ascent = true; // 当前日期晚于参数日期,则为真。默认为真。
// 如果在同一年中
if (this->year == date.year) {
return this->getDayOfYear() - date.getDayOfYear();
}
// 不在同一年中,且当前日期晚
if (this->year > date.year) {
startDate = &date;
endDate = this;
// 如果当前日期早
} else {
startDate = this;
endDate = &date;
ascent = false;
}
// 先加上开始日期到该年结束的天数
int offsetDays = startDate->getLeftDaysYear();
// 再加上开始日期和结束日期之间的所有年的天数 (不包括起止年)
for (int i = startDate->year + 1; i < endDate->year; i++) {
offsetDays += getYearDays(i);
}
// 再加上结束日期时,该年已经过的天数
offsetDays += endDate->getDayOfYear();
if (ascent) // 如果是升序
return offsetDays;
else // 如果是降序,返回负数
return 0 - offsetDays;
}
// 计算当前日期是本年的第几天
int Date::getDayOfYear() const {
int days = 0;
for (int i = 1; i<month; i++) {
days += daysPerMonth[i - 1];
}
days += day;
if (isLeapyear(year) && month > 2)
days++;
return days;
}
// 计算当前日期距本年结束还有几天
// 不包括当前日期这一天
int Date::getLeftDaysYear() const {
return getYearDays(year) - getDayOfYear();
}
// 计算某一年有多少天
int Date::getYearDays(int year) const {
if (isLeapyear(year))
return 366;
return 365;
}
// utility function to confirm proper day value based on month and year; handle leap years, too.
int Date::checkDay(int testDay) const {
if (testDay > 0 && testDay <= daysPerMonth[month - 1])
return testDay;
if (isLeapyear(year) && month == 2 && testDay == 29)
return testDay;
cout << "Invalid day (" << testDay << ") set to 1.\n";
return 1;
}
bool Date::isLeapyear(int year) const {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
void main() {
Date birthDate(1991, 1, 11); // 我的生日
birthDate.printFullYear(); // 打印:1969-08-11
cout << endl;
birthDate.printStandardYear(); // 打印:69-08-11
cout << endl;
birthDate.setSeparator('/');
birthDate.printFullYear(); // 打印:1969/08/11
cout << endl;
cout << endl;
Date date(2000, 2, 29);
cout << date.getDayOfYear() << endl;
cout << birthDate.fullYearsTo(date) << endl; // 打印:40,满四十岁
cout << date - birthDate << endl; // 打印14857,活了14857天了
Date date2(1949, 10, 1);
cout << birthDate - date2 << endl; // 打印-7254,共和国比我早诞生了7254天
}
const int Date::daysPerMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
istream & operator >>(istream &input, Date &date) {
input >> date.year >> date.month >> date.day;
return input;
}
ostream & operator <<(ostream &output, const Date &date) {
output << date.year << "-" << date.month << "-" << date.day;
return output;
}
Date.h
#ifndef DATE_H
#define DATE_H
#include <iostream>
using namespace std;
class Date {
friend istream & operator>>(istream &, Date &);
friend ostream & operator<<(ostream &, const Date &);
public:
// 默认构造函数,以fullyear的形式给出年月日,
// 默认值为1900年1月1日
// 同时设置日期分隔符为“-”
Date(int = 1900, int = 1, int = 1);
/// 设置、获取函数///
// 设置日期,如果有非法的月或日,将其置为
void setDate(int, int , int);
void setYear(int);
int getYear() const;
void setMonth(int);
int getMonth() const;
void setDay(int);
int getDay() const;
void setSeparator(char);
char getSeparator() const;
/// 输出函数,使用setfill和setw ///
void printFullYear() const; // 以YYYY-MM-DD的形式打印,比如2010-01-08
void printStandardYear() const; // 以YY-MM-DD的形式打印,比如2010-01-08
/// 计算函数 ///
// 计算当前日期与参数日期之间相差几个整年,注意参数为日期对象的引用
int fullYearsTo(const Date& date) const;
// 计算当前日期比参数日期晚了多少天(考虑闰年)。如果参数日期晚于当前日期,返回负数,注意参数为日期对象的引用。
int operator-(const Date& date) const;
// 计算当前日期是本年的第几天
int getDayOfYear() const;
// 计算当前日期距本年结束还有几天。不包括当前日期这一天
int getLeftDaysYear() const;
private:
int year;
int month;
int day;
char separator; // 日期分隔符
static const int daysPerMonth[12]; // 声明静态常变量,每月的天数。在.cpp文件中定义并初始化
int checkDay( int ) const; // 根据年和月,判断参数日期是否合法。
bool isLeapyear( int ) const; // 判断参数年是否是闰年。
int getYearDays( int ) const; // 计算参数年有多少天
};
#endif
Employee.cpp
#include <iostream>
#include <iomanip>
#include "Employee.h"
#include "Date.h"
using namespace std;
Employee::Employee(const string first, const string last,
const Date &dateOfBirth, const Date &dateOfHire)
: firstName(first), lastName(last),
birthDate(dateOfBirth),
hireDate(dateOfHire) { }
void Employee::print() const {
cout << lastName << ", " << firstName << " Hired: ";
cout << hireDate;
cout << ", Birthday: ";
cout << birthDate << endl;
}
int Employee::getAge(const Date& date) const {
return birthDate.fullYearsTo(date);
}
int Employee::getYearsWorked(const Date& date) const {
return hireDate.fullYearsTo(date);
}
int Employee::getDaysWorked(const Date& date) const {
return date - hireDate;
}
void main() {
Date birth(1969, 8, 11);
Date hire(1998, 4, 1);
Date today(2010, 4, 30);
Employee manager("Bob", "Blue", birth, hire);
cout << endl;
manager.print();
cout << "到";
today.printFullYear();
cout << "为止" << endl;
cout << " 雇员已满" << manager.getAge(today) << "岁" << endl;
cout << " 雇员已工作了" << manager.getDaysWorked(today) << "天" << endl;
}
Employee.h
#include <string>
#include "Date.h"
using namespace std;
class Employee {
public:
Employee(const string, const string, const Date &, const Date &);
void print() const;
// 计算员工在参数指定的日期时,满多少岁
int getAge(const Date &date) const;
// 计算该员工工作满了多少年
int getYearsWorked(const Date &date) const;
// 计算该员工工作了多少天
int getDaysWorked(const Date &date) const;
private:
string firstName;
string lastName;
const Date birthDate; // composition: member object
const Date hireDate;
};
2.2 设计一个 CD 播放机 CDPlayer
(1)问题描述
设计一个CD播放机CDPlayer,它能够播放CD中的歌。其中,CD类、CDPlayer
类的声明分别如下所示:
class CD {
public:
CD(string name, string songs[]);
string getSinger(); // 获得歌手的名称
string getSong(int index); // 获得某首歌的歌名
void listSongs(); // 列出CD的内容
private:
string singer; // 歌手的名字。
string songs[6]; // 每张专辑6首歌的名字。
};
class CDPlayer {
public:
CDPlayer();
/*提供给用户一个菜单,通过这个菜单,用户可以选择:
1. 插入CD
2. 播放CD
3. 弹出CD
0. 关机 */
void showMenu();
/*插入CD. void insertCD(CD* cd),形参是指向CD对象的指针。如果CDPlayer中已经
有CD,提示先取出CD;如果CDPlayer中没有CD,显示插入了哪位歌星的CD。*/
void insertCD(CD *cd);
/*弹出CD. CD *ejectCD(),返回值是指向该CD对象的指针。如果CDPlayer中已经有CD,
显示弹出了哪位歌星的CD,返回该CD的指针;如果CDPlayer中没有CD,提示CDPlayer中
没有CD,返回NULL。*/
CD *ejectCD();
/*播放CD。如果CDPlayer中已经有CD,显示正在播放哪位歌星的CD,并打印CD中歌曲的
清单;如果CDPlayer中没有CD,显示CDPlayer中没有CD,并提示用户插入CD。*/
void play();
private:
/* 插入CDPlayer中的CD,它是指向CD对象的指针。没有CD时,为null。使用指针,很
好地模拟 了CD对象不是播放器的一部分,播放器只是读取放入其中的CD的内容。*/
CD *cd;
bool cdIn; // CDPlayer中是否已经插入CD
};
主函数如下:
void main() {
string name;
string songs[6];
cout << "制造CD......" << endl;
// 输入歌手名字
cout << " Singer's Name: " << endl;
cin >> name; // 输入:周杰伦
// 输入该歌手的六首歌名(青花瓷、菊花台、双节棍等)
for (int i = 0; i < 6; i++) {
cout << " song" << (i+1) << "#: ";
cin >> songs[i];
}
CD cd(name, songs); //制造CD
cd.listSongs(); //显示CD的内容
CDPlayer player; //制造CDplayer
player.showMenu(); //生成播放机的按钮
/* 播放 */
player.play(); //打印:Please insert CD first
/* 插入CD */
player.insertCD(&cd); //打印:插入了周杰伦的CD......
/* 播放 */
player.play(); //打印:正在播放周杰伦的CD......
player.ejectCD(); //打印:弹出了周杰伦的CD......
/* 另造一张CD,歌手和歌的录入省略。*/
CD cd2(name2, songs2);
player.insertCD(&cd2);
player.play();
}
(2)问题要求
源代码
CD.cpp
#include <iostream>
#include <string>
#include "CD.h"
using namespace std;
CD::CD(string name, string songs[]) {
singer = name;
for (int i = 0; i < 6; i++)
CD::songs[i] = songs[i];
}
string CD::getSinger() {
return singer;
}
string CD::getSong(int index) {
return songs[index];
}
void CD::listSongs() {
cout << "Singer: " << singer << endl;
for (int i = 0; i < 6; i++)
cout << " " << (i + 1) << ". " << (*songs)[i] << endl;
}
CD.h
#include <string>
using namespace std;
class CD {
public:
CD(string name, string songs[]);
string getSinger();
string getSong(int index);
void listSongs();
private:
string singer; // 歌手的名字。
string songs[6]; // 每张专辑6首歌的名字。
};
CDPlayer.cpp
#include <iostream>
#include <string>
#include "CDPlayer.h"
using namespace std;
CDPlayer::CDPlayer() {
cd = NULL;
cdIn = false;
}
void CDPlayer::insertCD(CD *cd) {
if (cdIn)
cout << "CD already in, to change, eject it first......\n";
else {
CDPlayer::cd = cd;
cdIn = true;
cout << "插入了" << cd->getSinger() << "的CD......\n";
}
}
CD* CDPlayer::ejectCD() {
CD* temp = cd;
if (cdIn) {
cout << "弹出了" << cd->getSinger() << "的CD......\n";
cdIn = false;
cd = 0;
return temp;
} else {
cout << "No CD.\n";
return NULL;
}
}
void CDPlayer::play() {
if (cdIn) {
cout << "正在播放" << cd->getSinger() << "的CD......\n";
cd->listSongs();
/*for (int i = 0; i < 6; i++)
cout << " Song" << (i+1) << "#: " << cd->getSong(i) << endl;*/
} else
cout << "Please insert CD first\n";
}
void CDPlayer::showMenu() {
cout << endl;
cout << "**************************************\n";
cout << "* 1. 播放CD *\n";
cout << "* 2. 插入CD *\n";
cout << "* 3. 弹出CD *\n";
cout << "* 0. 关机 *\n";
cout << "**************************************\n";
}
int main() {
string name;
string songs[6];
cout << "\n制造CD......\n";
// 输入歌手名字
cout << " Singer's Name: ";
cin >> name; // 输入:周杰伦
// 输入该歌手的六首歌名(青花瓷、菊花台、三节棍等)
for (int i = 0; i < 6; i++) {
cout << " song" << (i + 1) << "#: ";
cin >> songs[i];
}
// 制造CD
CD cd(name, songs);
// 显示CD的内容
cd.listSongs();
// 制造CDplayer
CDPlayer player;
// 生成播放机的按钮
player.showButtons();
// 播放
player.play(); // 打印:Please insert CD first
// 插入CD
player.insertCD(&cd); // 打印:插入了周杰伦的CD......
// 播放
player.play(); // 打印:正在播放周杰伦的CD......
// song1#: 青花瓷
// song2#: 菊花台
// song3#: 三节棍
// song4#: 东风破
// song5#: 珊瑚海
// song6#: 稻香
player.ejectCD(); // 打印:弹出了周杰伦的CD......
return 0;
}
CDPlayer.h
#include "CD.h"
class CDPlayer {
public:
CDPlayer();
// 提供给用户一个菜单.
// 通过这个菜单,用户可以选择
// 1. 插入CD
// 2. 播放CD
// 3. 弹出CD
// 0. 关机
void showMenu();
// 插入CD,形参是指向CD对象的指针.
// 如果CDPlayer中已经有CD,提示先取出CD;
// 如果CDPlayer中没有CD,显示插入了哪位歌星的CD.
void insertCD(CD* cd);
// 弹出CD,返回值是指向该CD对象的指针.
// 如果CDPlayer中已经有CD,显示弹出了哪位歌星的CD,返回该CD的指针;
// 如果CDPlayer中没有CD,提示CDPlayer中没有CD,返回NULL.
CD* ejectCD();
// 播放CD.
// 如果CDPlayer中已经有CD,显示正在播放哪位歌星的CD;
// 如果CDPlayer中没有CD,显示CDPlayer中没有CD,
// 并提示用户插入CD.
void play();
private:
CD* cd; // 插入CDPlayer中的CD,它是指向CD对象的指针
bool cdIn; // CDPlayer中是否已经插入CD
};