钱能C++程序设计教程第10章继承学习笔记
2009-05-08 12:52
681 查看
1、继承结构:
基类(超类),派生类(子类)。派生类总是依附于基类,派生类对象中总是含有基类对象,即含有基类的数据成员。或者说,基类对象是派生类对象的组成部分。
2、访问父类成员
捆绑子类对象可以访问父类成员函数和自身成员函数;捆绑基类对象只能访问基类成员函数,不能访问子类成员函数。
类内访问控制。
继承分为公有继承,保护继承和私有继承。但一般来说以公有居多,此处不做详细讨论。
3、派生类的构造
默认构造。
如果派生类无默认构造函数,派生类的父类的构造函数必须有默认参数,否则会导致编译通不过,如课后习题第一题的错误
同时也可以再派生类的构造函数中规定调用基类构造函数形式。如:
4、继承方式分为三种。此处略去不谈。
5、继承与组合
类内含有对象成员的情形成为组合。继承和组合都重用了类设计。
5.1 性质差异
对于组合,成员对象的数据隐私是不能被直接访问的,必须通过成员对象的操作区间接访问。也就是累对象与成员对象之间是彼此独立的。
5.2 对象分析
对于继承,由于派生类与基类的性质的一致性,所以可以从基类的访问控制中获得对基类对象的数据成员直接访问的便利。
如,圆Circle类,包含中心点(Point类)位置和半径。但是Point类与Circle类之间谈不上继承的关系,因此此处使用组合更多的体现了精巧性。
二者最大的区别在于在组合中如果想调用对象的成员,必须而且只能调用公有的成员,对于私有的成员不可以访问,除非使用成员函数进行访问。但组合给人以清晰明了的感觉。圆不是从点继承来的,圆是由一个点和一个半径组成的,因此更多的时候,我们愿意从组合的角度来看待这个问题。
采用组合还是继承,应首先从两个类对象的性质来区分。性质相同的话,则一个类拥有另外一个类的大部分操作,此时选择继承会好一些,如果不同且四号纯粹的包含关系,那么组合就体现其优越性了。
6、多继承概念
多继承结构
7、虚拟继承
在虚拟继承下,main函数中的setWeight函数调用便不再模糊,得到了沙发床真正的多继承关系。
但最好是避免多继承的使用,因为现代程序已越来越淡化这方面的应用。
课后作业总结:
第3题:
同样,此题有另外一种方法。
第4题
同样也有另外一种方法
这种方法是第3题中的第二种方法的对象,即使用一天一天的加或者减,给出其中某一天的星期,根据日期的关系推导出最后的星期几。
基类(超类),派生类(子类)。派生类总是依附于基类,派生类对象中总是含有基类对象,即含有基类的数据成员。或者说,基类对象是派生类对象的组成部分。
class BaseClass { int a, b; //私有成员 public: //公有成员 }; class B : public BaseClass { int c; public: //公有成员 };
2、访问父类成员
捆绑子类对象可以访问父类成员函数和自身成员函数;捆绑基类对象只能访问基类成员函数,不能访问子类成员函数。
//f1001.cpp #include <iostream> #include <string> using namespace std; class Advisor { //导师类 int noOfMeeting; }; class Student { //学生类 string name; int semesterHours; double average; public: Student(string pName = "noName"):name(pName),average(0),semesterHours(0) {} //成员函数,构造 void addCourse(int hours, double grade) { //成员函数:加课程 double totalGrade = (semesterHours * average + grade); semesterHours += hours; average = semesterHours ? totalGrade/semesterHours : 0; } void display() { //成员函数:显示 cout << "name = " << name << "/ " << ",hours= " << semesterHours << ",average = " << average << endl; } int getHours() { return semesterHours;} //成员函数:取值 double getAverage() {return average;} //成员函数:取平均分 }; class GraduateStudent : public Student { Advisor advisor; int qualifierGrade; public: // GraduateStudent(int s = 0):qualifierGrade(s) {} int getQualifier() { return qualifierGrade;} }; int main () { // Student ds("Lo lee"); GraduateStudent gs; // ds.addCourse(3,2.5); // ds.display(); gs.addCourse(3,3.0); Student ds(gs); ds.display(); cout << ds.getAverage() << endl; // cout << gs.getHours() << endl; // cout << gs.getQualifier() << endl; }
类内访问控制。
继承分为公有继承,保护继承和私有继承。但一般来说以公有居多,此处不做详细讨论。
3、派生类的构造
默认构造。
如果派生类无默认构造函数,派生类的父类的构造函数必须有默认参数,否则会导致编译通不过,如课后习题第一题的错误
同时也可以再派生类的构造函数中规定调用基类构造函数形式。如:
//f1001.cpp #include <iostream> #include <string> using namespace std; class Advisor { int noOfMeeting; public: Advisor() { cout << "Advisor" << endl;} Advisor(const Advisor &) { cout << "copy Advisor " << endl;} ~Advisor() { cout << "~Advisor" << endl;} }; class Student { string name; int semesterHours; double average; public: Student(string pName = "noName"):name(pName),average(0),semesterHours(0) {} void addCourse(int hours, double grade) { double totalGrade = (semesterHours * average + grade); semesterHours += hours; average = semesterHours ? totalGrade/semesterHours : 0; } void display() { cout << "name = " << name << "/ " << ",hours= " << semesterHours << ",average = " << average << endl; } int getHours() { return semesterHours;} double getAverage() {return average;} ~Student() {cout << "~Student" << endl; } }; class GraduateStudent : public Student { Advisor advisor; int qualifierGrade; public: GraduateStudent(const string & PN, Advisor & adv):Student(PN),advisor(adv),qualifierGrade(0) {} //构造函数 void display() { Student::display(); cout << "GraduateStudent" << endl; } int getQualifier() { return qualifierGrade;} }; void fn(Advisor & advisor) { GraduateStudent gs("Yen Kay Doodle", advisor); gs.display(); } int main () { Advisor da; fn(da); }
4、继承方式分为三种。此处略去不谈。
5、继承与组合
类内含有对象成员的情形成为组合。继承和组合都重用了类设计。
5.1 性质差异
对于组合,成员对象的数据隐私是不能被直接访问的,必须通过成员对象的操作区间接访问。也就是累对象与成员对象之间是彼此独立的。
5.2 对象分析
对于继承,由于派生类与基类的性质的一致性,所以可以从基类的访问控制中获得对基类对象的数据成员直接访问的便利。
如,圆Circle类,包含中心点(Point类)位置和半径。但是Point类与Circle类之间谈不上继承的关系,因此此处使用组合更多的体现了精巧性。
#ifndef HEADER_POINT #define HEADER_POINT #include <iostream> using namespace std; class Point { //定义基类Point protected: //保护数据 double x, y; public: static double PI; //静态不变数据π public: Point (double a = 0, double b = 0); //构造函数 double xOffset() const; double yOffset() const; double angle() const; double radius() const; Point operator+(const Point & d) const; Point & operator+=(const Point & d); //加号重载 void moveTo(double a, double b); //移动函数 friend inline ostream & operator<< (ostream & o, const Point & d) { //输出流函数 return o << '(' << d.x << ',' << d.y << ')' << endl; } }; #endif #include "point.h" #include <cmath> using namespace std; double Point::PI = 3.14159265; Point::Point(double a, double b):x(a), y(b) {} //默认参数不用带 double Point::xOffset() const { return x; } double Point::yOffset() const { return y; } double Point::angle() const { return (180/PI)*atan2(y,x);} double Point::radius() const {return sqrt(x*x+y*y);} void Point::moveTo(double a, double b) { x = a, y = b;} Point Point::operator+(const Point & d) const { return Point(x+d.x, y+d.y); } //加号重载 Point & Point::operator+=(const Point & d) { //+=重载 x += d.x; y += d.y; return *this; } //继承设计circle_inher.h #ifndef HEADER_CIRCLE_INHER #define HEADER_CIRCLE_INHER #include "point.h" class Circle : public Point { //继承了Point double radius; //派生半径 public: Circle (const Point & p = Point(), double r = 0); //带默认参数的构造函数 double getRadius() const; //返回半径 Point getPoint () const; //返回圆心(圆心为Point类) double getArea() const; //返回面积 double getCircum() const; //返回周长 void moveTo(double a, double b); //移动函数 void modifyRadius(double r); //修改半径 }; #endif //circle_inhe.cpp #include "point.h" #include "circle_inher.h" Circle::Circle (const Point & p, double r) : Point(p), radius(r){} double Circle::getRadius() const { return radius; } Point Circle::getPoint () const { return *static_cast<const Point*> (this);} double Circle::getArea() const { return radius * radius * Point::PI; } double Circle::getCircum() const { return 2 * radius * Point::PI; } void Circle::moveTo(double a, double b) { x = a, y = b} void Circle::modifyRadius(double r) { radius = r; } //组合设计circle_compos.h #ifndef HEADER_CIRCLE_COMPOS #define HEADER_CIRCLE_COMPOS #include "point.h" class Circle { private: //采用组合的方式使得可以设置成私有数据 Point point; double radius; public: Circle(const Point & p = Point(), double r = 0); double getRadius() const; Point getPoint() const; double getArea() const; double getCircum () const; void moveTo(double a, double b); void modifyRadius(double r); }; #endif //HEADER_CIRCLE_COMPOS //circle_compos.cpp #include "circle_compos.h" #include "point.h" Circle::Circle(const Point & p, double r) : point(p), radius(r) {} double Circle::getRadius() const { return radius; } Point Circle::getPoint() const { return point; } double Circle::getArea() const { return radius * radius * Point::PI; } double Circle::getCircum() const { return 2 * radius * Point::PI; } void Circle::moveTo(double a, double b) { point.moveTo(a,b);} void Circle::modifyRadius(double r) { radius = r; }
二者最大的区别在于在组合中如果想调用对象的成员,必须而且只能调用公有的成员,对于私有的成员不可以访问,除非使用成员函数进行访问。但组合给人以清晰明了的感觉。圆不是从点继承来的,圆是由一个点和一个半径组成的,因此更多的时候,我们愿意从组合的角度来看待这个问题。
采用组合还是继承,应首先从两个类对象的性质来区分。性质相同的话,则一个类拥有另外一个类的大部分操作,此时选择继承会好一些,如果不同且四号纯粹的包含关系,那么组合就体现其优越性了。
6、多继承概念
多继承结构
/* * f1006.cpp * 多重继承 */ #include <iostream> using namespace std; class Bed { protected: int weight; public: Bed () : weight(0) {} void sleep () const { cout <<"Sleeping.../n"; } void setWeight (int i) { weight= i; } }; class Sofa { protected: int weight; public: Sofa() : weight(0) {} void watchTV () const { cout <<"Watching TV./n"; } void setWeight (int i) { weight= i; } }; class SleeperSofa : public Bed, public Sofa { public: SleeperSofa () {} void foldOut () const { cout <<"Fold out the sofa./n"; } }; int main () { SleeperSofa ss; ss.watchTV(); ss.foldOut(); ss.sleep(); }
7、虚拟继承
/* * f1008.cpp * virtual inheritance */ #include <iostream> using namespace std; class Furniture { protected: int weight; public: Furniture () {} void setWeight (int i) { weight= i; } int getWeight () const { return weight; } }; class Bed : virtual public Furniture{ public: Bed () {} void sleep () const { cout <<"Sleeping.../n"; } }; class Sofa : virtual public Furniture { public: Sofa () {} void watchTV () const { cout <<"Watching TV./n"; } }; class SleeperSofa : public Bed, public Sofa { public: SleeperSofa () : Sofa(), Bed() {} void foldOut () const { cout <<"Fold out the sofa./n"; } }; int main () { SleeperSofa ss; ss.setWeight( 20); cout <<ss.getWeight() <<endl; }
在虚拟继承下,main函数中的setWeight函数调用便不再模糊,得到了沙发床真正的多继承关系。
但最好是避免多继承的使用,因为现代程序已越来越淡化这方面的应用。
课后作业总结:
第3题:
//ex03.cpp 第一种方法 //此处使用了Date和DateOperator两个类,DateOperator是集成了Date类的。 //在DateOperator中没有设置私有成员,但是设置了两个公有的成员函数AddDate和MinusDate,这两个函数分别可以计算加上某一个天数之后的日期和两个日期相隔的天数 //在f0904.cpp的基础上设计一个子类,且此子类可以进行加天数操作获得另一个日期和进行日期减日期操作获得相隔天数。 //创建2005.8.21和2008.8.8两个日期,并计算中间相隔的天数,前者加上300天会是哪个日期。 #include <iostream> #include <iomanip> using namespace std; int sumdaysOfmonth[13]={0,31,59,90,120,151,181,212,243,273,304,334,365}; class Date; ostream & operator << (ostream & o, const Date & d); class Date { //父类Date public: int year, month, day; void check(); //检验所创建的日期对象是否合法函数 public: Date (int y = 2000, int m = 1, int d = 1); //构造函数 Date (const string & s); //拷贝构造函数 bool isLeapYear () const; //判断是否为闰年函数 friend ostream & operator << (ostream & o, const Date & d); //输出流操作 }; void Date::check () { if (year>5000 || year<1 || month<1 || month>12 || day<1 || day>31) exit(1); } Date::Date(const string & s) { year = atoi(s.substr(0,4).c_str()); month = atoi(s.substr(5,2).c_str()); day = atoi(s.substr(8,2).c_str()); check(); } Date::Date(int y, int m, int d) { year = y, month = m, day = d; check(); } bool Date::isLeapYear () const { return (year%4 == 0 && year%100 != 0)|| (year%400 == 0) ; } ostream & operator << (ostream & o, const Date & d) { o << setfill ('0') << setw(4) << d.year << '-' << setw(2) << d.month << '-' << setw(2) << d.day << endl << setfill(' '); return o; } class DateOperate : public Date { public: DateOperate(int y, int m, int d) : Date(y,m,d) {}; //构造函数 int AddDate (int days) { //日期加天数的成员函数 int flag_Leap, sumdays; //闰年标记flag_Leap,总天数sumdays flag_Leap = month > 2 ? isLeapYear():0; //闰年为1,不是闰年都是0 sumdays = sumdaysOfmonth[month-1] + day + days + flag_Leap; //得出year开始之后的总天数 while (sumdays > 365 && isLeapYear() == 0 || sumdays > 366 && isLeapYear() == 1) { //求出year的值 sumdays = sumdays - 365 - isLeapYear(); year++; } flag_Leap = isLeapYear(); //判断对year操作之后的数是否为闰年 int i; for (i = 3; i <= 12; i++) //求出month和day的值 if (sumdays > sumdaysOfmonth[i-1] + flag_Leap && sumdays < sumdaysOfmonth[i] + flag_Leap) break; if (i == 13 && sumdays < sumdaysOfmonth[1]) { month = 1; day = sumdays; } else if (i == 13 && sumdays > sumdaysOfmonth[1] && sumdays < sumdaysOfmonth[2] + flag_Leap) { month = 2; day = sumdays - sumdaysOfmonth[1]; } else { month = i; day = sumdays - sumdaysOfmonth[month-1] - flag_Leap; } return 0; } int MinusDate (const Date d2) { int sumdays_d1, sumdays_d2, days, years; years = d2.year - year; //计算相隔的年数 int year_Leap = 0; for (int i = year; i <= d2.year; i++) { //计算相隔的年数中有无闰年,如果有闰年,则标记量year_Leap+1 if((i%4 == 0 && i%100 != 0)|| (i%400 == 0)) year_Leap++; } sumdays_d1 = sumdaysOfmonth[month-1] + day; //计算初始的日期的当年的天数 sumdays_d2 = sumdaysOfmonth[d2.month-1] + d2.day; //计算参数日期的当年的天数 days = 365*years + year_Leap + sumdays_d2 - sumdays_d1; //计算总的相差的天数 return days; //返回天数 } }; int main () { DateOperate d(2005,8,21); cout << "创建日期:" << d; Date e(2008,8,8); cout << "创建日期:" << e; cout << "相隔的天数为:" << d.MinusDate(e) << endl; d.AddDate(300); cout << "2005.8.21加上300天为: " << d; }
同样,此题有另外一种方法。
/* * exercise 10.3 * modification of f0904 */ #include <iostream> #include <iomanip> #include <cstdlib> using namespace std; class Date { int year, month, day; public: Date (const string &s); Date (int y =2000, int m =1, int d =1); int daysFrom (Date other); Date addDays (int n); friend ostream &operator << (ostream &o, const Date &d); int getYear() { return year; } int getMonth() { return month; } int getDay() { return day; } private: void makeValidDate (); int compareTo (Date other); int daysPerMonth (int y, int m); bool isLeapYear (int year); Date nextDay (); Date previousDay (); static int DAYS_PER_MONTH[]; const static int GREGORIAN_START_YEAR = 1582; const static int GREGORIAN_START_MONTH = 10; const static int GREGORIAN_START_DAY = 15; const static int JULIAN_END_DAY = 4; const static int JANUARY = 1; const static int FEBRUARY = 2; const static int DECEMBER = 12; }; int Date::DAYS_PER_MONTH[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /* Constructs a day with a given year, month, and day of the Julian/Gregorian calendar. The Julian calendar is used for all days before October 15, 1582 year != 0 month between 1 and 12 day between 1 and 31 */ void Date::makeValidDate () { if (year == 0 || month < JANUARY || DECEMBER < month || day < 1 || 31 < day) exit( 1); } Date::Date (const string &s) { year = atoi( s.substr( 0, 4).c_str()); month= atoi( s.substr( 5, 2).c_str()); day = atoi( s.substr( 8, 2).c_str()); makeValidDate(); } Date::Date (int y, int m, int d) { year= y, month= m, day= d; makeValidDate(); } int Date::daysPerMonth (int y, int m) { int days = DAYS_PER_MONTH[ m]; if (m == FEBRUARY && isLeapYear( y)) days= 29; return days; } bool Date::isLeapYear (int year) { if (y % 4 != 0) return false; if (y < GREGORIAN_START_YEAR) return true; return (y % 100 != 0) || (y % 400 == 0); } int Date::compareTo (Date other) { if (year > other.year) return 1; if (year < other.year) return -1; if (month > other.month) return 1; if (month < other.month) return -1; return day - other.day; } Date Date::addDays (int n) { Date result = *this; while (n > 0) { result = result.nextDay(); n--; } while (n < 0) { result = result.previousDay(); n++; } return result; } int Date::daysFrom (Date other) { int n = 0; Date d = *this; while (d.compareTo( other ) > 0) { d = d.previousDay(); n++; } while (d.compareTo( other ) < 0) { d = d.nextDay(); n--; } return n; } Date Date::nextDay() { int y = year; int m = month; int d = day; if (y == GREGORIAN_START_YEAR && m == GREGORIAN_START_MONTH && d == JULIAN_END_DAY) d = GREGORIAN_START_DAY; else if (d < daysPerMonth( y, m )) d++; else { d = 1; m++; if (m > DECEMBER) { m = JANUARY; y++; if (y == 0) y++; } } return *(new Date( y, m, d)); } Date Date::previousDay () { int y = year; int m = month; int d = day; if (y == GREGORIAN_START_YEAR && m == GREGORIAN_START_MONTH && d == GREGORIAN_START_DAY) d = JULIAN_END_DAY; else if (d > 1) d--; else { m--; if (m < JANUARY) { m = DECEMBER; y--; if (y == 0) y--; } d = daysPerMonth( y, m); } return *(new Date( y, m, d)); } ostream &operator << (ostream &o, const Date &d) { return o <<setfill( '0') <<setw( 4) <<d.year <<'-' <<setw( 2) <<d.month <<'-' <<setw( 2) <<d.day <<setfill( ' '); } int main () { Date d1( "2005.08.21"); cout << d1.addDays( 300) << endl; Date d2( "2005.08.21"); Date d3( 2008, 8, 8); cout << d3.daysFrom( d2) << endl; }
第4题
#pragma once #ifndef DATE #define DATE #include <iostream> using namespace std; #include <string> class Date { //父类Date public: int year, month, day; void check(); //检验所创建的日期对象是否合法函数 public: Date (int y = 2000, int m = 1, int d = 1); //构造函数 Date (const string & s); //拷贝构造函数 bool isLeapYear () const; //判断是否为闰年函数 }; #endif //Date.cpp #include <iomanip> #include "Date.h" void Date::check () { if (year>5000 || year<1 || month<1 || month>12 || day<1 || day>31) exit(1); } Date::Date(const string & s) { year = atoi(s.substr(0,4).c_str()); month = atoi(s.substr(5,2).c_str()); day = atoi(s.substr(8,2).c_str()); check(); } Date::Date(int y, int m, int d) { year = y, month = m, day = d; check(); } bool Date::isLeapYear () const { return (year%4 == 0 && year%100 != 0)|| (year%400 == 0) ; } #pragma once //WDate类 #include "Date.h" class WDate : public Date { int weekday,y,c,m,d; public: WDate(int y, int m, int d); //构造函数 int GetWeekDay (); //获得星期几 friend ostream & operator << (ostream & o, const WDate & w); //输出流操作(输出包括星期几在内的信息) }; /*蔡勒(Zeller)公式:w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 公式中的符号含义如下,w:星期;c:世纪-1;y:年(两位数);m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来 计算,比如2003年1月1日要看作2002年的13月1日来计算);d:日;[ ]代表取整,即只要整数部分。 */ //WDate.cpp #ifndef WDATE #define WDATE #include "WDate.h" #include <iomanip> #include <string> WDate::WDate(int y, int m, int d):Date(y,m,d) {}; //构造函数 int WDate::GetWeekDay(){ //获得星期几 y = year%100; c = year/100; (month == 1 || month == 2) ? m = month + 12 : m = month; d = day; weekday = y + y/4 + c/4 -2*c + 26*(m+1)/10 + d -1; return weekday%7; } ostream & operator << (ostream & o,const WDate & w) { o << setfill ('0') << setw(4) << w.year << '-' << setw(2) << w.month << '-' << setw(2) << w.day << setfill(' '); return o; } #endif //ex04.cpp //在第3题Date类的基础上,继承一个WDate类,它包含了星期几信息,因而,显示日期的成员要做修改,应同时显示星期几。另外,还要增加获得星期几的成员 //创建2005.8.21和2008.8.8两个日期,分别显示这两个日期 #include "WDate.h" #include <iostream> static const char* weekName[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thusday", "Friday", "Saturday" }; int main () { WDate d(2005,8,21); cout << "创建日期:" << d; cout << " " << weekName[d.GetWeekDay()] << endl; WDate e(2009,4,29); cout << "创建日期:" << e; cout << " " << weekName[e.GetWeekDay()] << endl; }
同样也有另外一种方法
/* * exercise 10.4 * Class WDate */ #include <iostream> #include <iomanip> #include <cstdlib> using namespace std; class Date { int year, month, day; public: Date (const string &s); Date (int y =2000, int m =1, int d =1); int daysFrom (Date other); Date addDays (int n); friend ostream &operator << (ostream &o, const Date &d); int getYear() { return year; } int getMonth() { return month; } int getDay() { return day; } private: void makeValidDate (); int compareTo (Date other); int daysPerMonth (int y, int m); bool isLeapYear (int year); Date nextDay (); Date previousDay (); static int DAYS_PER_MONTH[]; const static int GREGORIAN_START_YEAR = 1582; const static int GREGORIAN_START_MONTH = 10; const static int GREGORIAN_START_DAY = 15; const static int JULIAN_END_DAY = 4; const static int JANUARY = 1; const static int FEBRUARY = 2; const static int DECEMBER = 12; }; int Date::DAYS_PER_MONTH[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; /* Constructs a day with a given year, month, and day of the Julian/Gregorian calendar. The Julian calendar is used for all days before October 15, 1582 year != 0 month between 1 and 12 day between 1 and 31 */ void Date::makeValidDate () { if (year == 0 || month < JANUARY || DECEMBER < month || day < 1 || 31 < day) exit( 1); } Date::Date (const string &s) { year = atoi( s.substr( 0, 4).c_str()); month= atoi( s.substr( 5, 2).c_str()); day = atoi( s.substr( 8, 2).c_str()); makeValidDate(); } Date::Date (int y, int m, int d) { year= y, month= m, day= d; makeValidDate(); } int Date::daysPerMonth (int y, int m) { int days = DAYS_PER_MONTH[ m]; if (m == FEBRUARY && isLeapYear( y)) days= 29; return days; } bool Date::isLeapYear (int year) { if (y % 4 != 0) return false; if (y < GREGORIAN_START_YEAR) return true; return (y % 100 != 0) || (y % 400 == 0); } int Date::compareTo (Date other) { if (year > other.year) return 1; if (year < other.year) return -1; if (month > other.month) return 1; if (month < other.month) return -1; return day - other.day; } Date Date::addDays (int n) { Date result = *this; while (n > 0) { result = result.nextDay(); n--; } while (n < 0) { result = result.previousDay(); n++; } return result; } int Date::daysFrom (Date other) { int n = 0; Date d = *this; while (d.compareTo( other ) > 0) { d = d.previousDay(); n++; } while (d.compareTo( other ) < 0) { d = d.nextDay(); n--; } return n; } Date Date::nextDay() { int y = year; int m = month; int d = day; if (y == GREGORIAN_START_YEAR && m == GREGORIAN_START_MONTH && d == JULIAN_END_DAY) d = GREGORIAN_START_DAY; else if (d < daysPerMonth( y, m )) d++; else { d = 1; m++; if (m > DECEMBER) { m = JANUARY; y++; if (y == 0) y++; } } return *(new Date( y, m, d)); } Date Date::previousDay () { int y = year; int m = month; int d = day; if (y == GREGORIAN_START_YEAR && m == GREGORIAN_START_MONTH && d == GREGORIAN_START_DAY) d = JULIAN_END_DAY; else if (d > 1) d--; else { m--; if (m < JANUARY) { m = DECEMBER; y--; if (y == 0) y--; } d = daysPerMonth( y, m); } return *(new Date( y, m, d)); } ostream &operator << (ostream &o, const Date &d) { return o <<setfill( '0') <<setw( 4) <<d.year <<'-' <<setw( 2) <<d.month <<'-' <<setw( 2) <<d.day <<setfill( ' '); } class WDate : public Date { int wday; public: WDate (int y, int m, int d) : Date(y, m, d), wday(0) { const Date REFERENCE_DAY( 2001, 1, 1); // It was a Monday. Date theDate( y, m, d); int days = theDate.daysFrom( REFERENCE_DAY ); wday = ((days + 1) % 7 + 7) % 7; } int getWday() { return wday; } friend ostream &operator << (ostream &o, WDate &d) { const char *WorkDay[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; return o <<(Date)d <<" " <<WorkDay[ d.getWday()]; } }; int main () { WDate d1( 2005, 8, 21); WDate d2( 2008, 8, 8); WDate d3( 2009, 5, 6); WDate d4( 2000, 12, 31); cout <<d1 <<endl <<d2 <<endl <<d3 <<endl <<d4 <<endl; }
这种方法是第3题中的第二种方法的对象,即使用一天一天的加或者减,给出其中某一天的星期,根据日期的关系推导出最后的星期几。
相关文章推荐
- C_PlusPlus学习笔记 - 6_继承与派生(C++语言程序设计【第三版】 郑莉等,清华大学出版社)
- C++ 学习笔记(15)面向对象程序设计(类、继承、虚函数、抽象类、using命令、容器与继承)
- 面向对象与C++程序设计-类的继承与派生学习笔记
- C++学习笔记(第14章->代码重用->包含,继承,多重继承,虚基类)
- c++中子类的继承和调用父类构造函数的方法——学习c++笔记
- C++学习笔记--继承与多态
- C++入门学习笔记(四)--继承与多态
- 嵌入式开发之C++基础学习笔记4--面向对象封装继承多态
- 钱xx的 C++程序设计教程 夹在书里的笔记
- JavaScript高级程序设计-学习笔记5(继承)
- C++学习笔记19 多态与继承
- C++ FAQ学习笔记 21章 继承 — 适当的继承和可置换性
- JS高级程序设计学习笔记——继承
- C++ 学习笔记(18)异常处理(noexcept说明符和noexcept运算符、构造函数的try和catch)、命名空间(using声明和using指示)、多继承(虚继承)
- c++学习笔记 -- 继承(3)
- 【C++】【学习笔记】【029】虚继承
- C++程序设计语言学习笔记(二)
- c++学习笔记--继承的赋值
- C++学习笔记13,private继承,私有继承(四)
- C++学习笔记--继承中的同名变量和同名函数