1. 示例:使用引用的"Time"类
回到之前版本的"Time"类,假设我们想增加链式操作,例如t.nextSecond().nextSecond().print()
,我们就需要让nextSecond()
返回this
的一个引用。
Time.h
1class Time {
2private:
3 ......
4public:
5 Time &nextSecond(); // Return a reference to "this" instance
6 ......
7}
在函数原型中,我们申明了一个nextSecond()
的成员函数,返回Time
对象的引用。返回的引用可以用来继续调用成员函数。
Time.cpp
1// Increase this instance by one second and return this instance by reference.
2Time &Time::nextSecond() {
3 if (++second == 60) {
4 second = 0;
5 if (++minute == 60) {
6 minute = 0;
7 if (++hour = 24) {
8 hour = 0;
9 }
10 }
11 }
12
13 return *this; // Return this instance by reference
14 // "this" is a pointer to this instance. *this refers to the instance.
15}
C++有一个关键字"this",它保存了一个指向当前实例的指针。也就是说,*this
指的是当前实例。
TestTime.cpp
1Time t1(23, 59, 58);
2t1.print();
3t2.nextSecond();
4t1.print();
5t1.nextSecond().nextSecond().print();
6t1.print();
2. 示例:Time"类的第三个版本,异常处理
输入检验是必要的,例如,在setHour(int h)
函数中,我们需要检验输入的参数是 0~23 之间的数字。校验参数很简单,但是如果校验失败的话我们该如何处理错误呢,我们是输出一句错误
提示然后终止程序呢,还是输出一个警告,然后继续执行程序直到错误不能被容忍为止呢?这两种方式都不好。
1void Time::setHour(int h) {
2 if (h >= 0 && h <= 23) {
3 hour = h;
4 } else {
5 cout << "Error: Invalid hour! Hour shall be 0~23." << endl;
6 exit(1);
7 }
8}
1void Time::setHour(int h) {
2 if (h >= 0 && h <= 23) {
3 hour = h;
4 } else {
5 cout << "Warning: Invalid hour! Hour shall be 0-23." << endl;
6 hour = 0;
7 }
8}
取而代之的是,C++提供了一种异常处理机制(在头文件
Time.h
1#ifndef TIME_H
2#define TIME_H
3
4class Time {
5private:
6 int hour;
7 int minute;
8 int second;
9
10public:
11 Time(int h = 0, int m = 0, int s = 0);
12 int getHour() const;
13 void setHour(int h);
14 int getMinute() const;
15 void setMinute(int m);
16 int getSecond() const;
17 void setSecond(int s);
18 void setTime(int h, int m, int s);
19 void print() const;
20};
21
22#endif
Time.cpp
1#include <iostream>
2#include <iomanip>
3#include <stdexcept>
4#include "Time.h"
5
6using namespace std;
7
8Time::Time(int h, int m, int s) {
9 setHour(h);
10 setMinute(m);
11 setSecond(s);
12}
13
14int Time::getHour() const {
15 return hour;
16}
17
18void Time::setHour(int h) {
19 if (h >= 0 && h <= 23) {
20 hour = h;
21 } else {
22 throw invalid_argument("Invalid hour! Hour shall be 0~23.");
23 }
24}
25
26int Time::getMinute() const {
27 return minute;
28}
29
30void Time::setMinute(int m) {
31 if (m >= 0 && m <= 59) {
32 minute = m;
33 } else {
34 throw invalid_argument("Invalid minute! Minute shall be 0~59.");
35 }
36}
37
38int Time::getSecond() const {
39 return second;
40}
41
42void Time::setSecond(int s) {
43 if (s >= 0 && s <= 59) {
44 second = s;
45 } else {
46 throw invalid_argument("Invalid second! Second shall be 0~59.");
47 }
48}
49
50void Time::setTime(int h, int m, int s) {
51 setHour(h);
52 setMinute(m);
53 setSecond(s);
54}
55
56void Time::print() const {
57 cout << setfill('0');
58 cout << setw(2) << hour << ":" << setw(2) << minute << ":"
59 << setw(2) << second << endl;
60}
TestTime.cpp
1#include <iostream>
2#include <stdexcept>
3
4#include "Time.h"
5
6using namespace std;
7
8int main() {
9 try {
10 Time t1(25, 0, 0);
11 t1.print();
12 } catch (invalid_argument &ex) {
13 cout << "Exception:" << ex.what() << endl;
14 }
15
16 cout << "Next statement after try-catch" << endl;
17}
3. 对象引用,指针和数组中的动态内存分配(高级)
1#include <iostream>
2#include "Time.h"
3using namespace tsd;
4
5int main() {
6 Time t1(1, 2, 3);
7 t1.print();
8
9 Time *ptrT1 = &t1;
10 (*ptrT1).print();
11 ptrT1->print();
12
13 Time &refT1 = t1;
14 refT1.print();
15
16 Time *ptrT2 = new Time(4, 5, 6);
17 ptrT2->print();
18 delete ptrT2;
19
20 Time tArray1[2];
21 tArray1[0].print();
22 tArray1[1].print();
23
24 Time tArray2[2] = {Time(7, 8, 9), Time(10)};
25 tArray2[0].print();
26 tArray2[1].print();
27
28 Time *ptrTarray3 = new Time[2];
29 ptrTarray3[0].print();
30 ptrTarray3[1].print();
31 delete[] ptrTarray3;
32
33 // C++11 syntax, compile with -std=c++0x
34 Time *ptrTarray4 = new Time[2] {Time(11, 12, 13), Time(14)};
35 ptrTarray4->print();
36 (ptrTarray4 + 1)->print();
37 delete[] ptrTarray4;
38}
4. 示例:复数类
下面是复数类的类图
Complex.h
1#ifndef COMPLEX_H
2#define COMPLEX_H
3
4class Complex {
5private:
6 double real;
7 double imag;
8
9public:
10 Complex(double real = 0.0, double imag = 0.0);
11 double getReal() const;
12 void setReal(double real);
13 double getImag() const;
14 void setImag(double imag);
15 void setValue(double real, double imag);
16 void print() const;
17 bool isReal() const;
18 bool isImaginary() const;
19
20 Complex &addInto(const Complex &another);
21 Complex &addInto(double real, double imag);
22
23 Complex addReturnNew(const Complex *another) const;
24 Complex addReturnNew(double real, double imag) const;
25};
26#endif
Complex.cpp
1#include <iostream>
2#include "Complex.h"
3
4using namespace std;
5
6Complex::Complex(double real, double imag) : real(real), imag(imag) {}
7
8double Complex::getReal() const {
9 return real;
10}
11
12void Complex::setReal(double real) {
13 this->real = real;
14}
15
16double Complex::getImag() const {
17 return imag;
18}
19
20void Complex::setImag(double imag) {
21 this->imag = imag;
22}
23
24void Complex::setValue(double real, double imag) {
25 this->real = real;
26 this->imag = imag;
27}
28
29void Complex::print() const {
30 cout << '(' << real << ',' << imag << ')' << endl;
31}
32
33bool Complex::isReal() const {
34 return (imag == 0);
35}
36
37bool Complex::isImaginary() const {
38 return (imag != 0);
39}
40
41Complex &Complex::addInto(const Complex &another) {
42 real += another.real;
43 imag += another.imag;
44 return *this;
45}
46
47Complex &Complex::addInto(double real, double imag) {
48 this->real += real;
49 this->imag += imag;
50 return *this;
51}
52
53Complex Complex::addReturnNew(const Complex &another) const {
54 return Complex(real + another.real, imag + another.imag);
55}
56
57Complex Complex::addReturnNew(double real, double imag) const {
58 return Complex(this->real + real, this->imag + imag);
59}
TestComplex.cpp
1#include <iostream>
2#include <iomanip>
3#include "Complex.h"
4
5using namespace std;
6
7int main() {
8 Complex c1, c2(4, 5);
9 c1.print();
10 c2.print();
11
12 c1.setValue(6, 7);
13 c1.print();
14
15 c1.setReal(0);
16 c1.setImag(8);
17 c1.print();
18
19 cout << boolalpha; // print true/false instead of 0/1
20 cout << "Is real?" << c1.isReal() << endl;
21 cout << "Is Imaginary?" << c1.isImaginary() << endl;
22
23 c1.addInto(c2).addInto(1, 1).print();
24 c1.print();
25
26 c1.addReturnNew(c2).print();
27 c1.print();
28 c1.addReturnNew(1, 1).print();
29 c1.print();
30
31 return 0;
32}
**注意:**不要返回一个局部变量的引用!
假设我们将addReturnNew
函数修改为下面的样子:
1Complex &Complex::addReturnNew(const Complex &another) const {
2 return Complex(real + another.real, imag + another.imag);
3}
那么在编译的时候会报以下错误:“invalid initialization of non-const reference of type ‘Complex&’ from an rvalue of type ‘Complex’"。 这是因为临时变量是在函数体内构造的,不能作用于函数体外,从而外部调用的引用就是非法的。
5. 示例:Date"类
Date.h
1#ifndef DATE_H
2#define DATE_H
3
4#include <string>
5
6using namespace std;
7
8class Date {
9private:
10 int year;
11 int month;
12 int day;
13 const static string STR_MONTHS[];
14 const static string STR_DAYS[];
15 const static int DAYS_IN_MONTHS[];
16 const static int YRER_MIN = 1753;
17 const static int YRER_MAX = 9999;
18
19public:
20 static bool isLeapYear(int y);
21 static bool isValidDate(int y, int m, int d);
22 static int getDayOfWeek(int y, int m, int d);
23
24 Date(int y, int m, int d);
25 void setDate(int y, int m, int d);
26 int getYear() const;
27 int getMonth() const;
28 int getDay() const;
29 void setYear(int y);
30 void setMonth(int m);
31 void setDay(int d);
32 void print() const;
33
34 Date &nextDay();
35 Date &previousDay();
36 Date &nextMonth();
37 Date &previousMonth();
38 Date &nextYear();
39 Date &previousYear();
40};
41#endif
Date.cpp
1/* Implementation for Date Class (Date.cpp) */
2#include <iostream>
3#include <stdexcept>
4#include "Date.h"
5using namespace std;
6
7// Initialize static non-integer variable (must be done outside the class declaration)
8const string Date::STR_MONTHS[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
9 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
10
11const int Date::DAYS_IN_MONTHS[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
12
13const string Date::STR_DAYS[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
14 "Thursday", "Friday", "Saturday"};
15
16// A static function that returns true if the given year is a leap year
17bool Date::isLeapYear(int year) {
18 return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
19}
20
21// A static function that returns true if the given y, m, d constitutes a valid date
22bool Date::isValidDate(int y, int m, int d) {
23 if (y >= YEAR_MIN && y <= YEAR_MAX && m >= 1 && m <= 12) {
24 int lastDayOfMonth = DAYS_IN_MONTHS[m-1];
25 if (m == 2 && isLeapYear(y)) {
26 lastDayOfMonth = 29;
27 }
28 return (d >= 1 && d <= lastDayOfMonth);
29 } else {
30 return false;
31 }
32}
33
34// A static function that returns the day of the week (0:Sun, 6:Sat) for the given date
35// Wiki "Determination of the day of the week" for the algorithm
36int Date::getDayOfWeek(int y, int m, int d) {
37 int centuryTable[] = {4, 2, 0, 6, 4, 2, 0, 6}; // 17xx, 18xx, ...
38 int MonthTable[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
39 int MonthLeapYearTable[] = {6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
40
41 int century = y / 100;
42 int twoDigitYear = y % 100;
43 int centuryTableIndex = (century - 17) % 8;
44 // Date before 17xx are not valid, but needed to prevent negative index
45 if (centuryTableIndex < 0) {
46 centuryTableIndex += 8;
47 }
48 int sum = centuryTable[centuryTableIndex] + twoDigitYear + twoDigitYear / 4;
49 if (isLeapYear(y)) {
50 sum += MonthLeapYearTable[m-1];
51 } else {
52 sum += MonthTable[m-1];
53 }
54 sum += d;
55 return sum % 7;
56}
57
58// Constructor
59Date::Date(int y, int m, int d) {
60 setDate(y, m, d);
61}
62
63// With Input validation
64void Date::setDate(int y, int m, int d) {
65 setYear(y);
66 setMonth(m);
67 setDay(d); // need to set the day after year and month
68}
69
70int Date::getYear() const {
71 return year;
72}
73
74void Date::setYear(int y) {
75 if (y >= YEAR_MIN && y <= YEAR_MAX) {
76 year = y;
77 } else {
78 throw invalid_argument("Error: Invalid year (1753-9999)!");
79 }
80}
81
82int Date::getMonth() const {
83 return month;
84}
85
86void Date::setMonth(int m) {
87 if (m >= 1 && m <= 12) {
88 month = m;
89 } else {
90 throw invalid_argument("Error: Invalid month (1-12)!");
91 }
92}
93
94int Date::getDay() const {
95 return day;
96}
97
98// Assuming that the year and month are already set
99void Date::setDay(int d) {
100 int lastDayOfMonth = DAYS_IN_MONTHS[month-1];
101 if (month == 2 && isLeapYear(year)) {
102 lastDayOfMonth = 29;
103 }
104 if (d >= 1 && d <= lastDayOfMonth) {
105 day = d;
106 } else {
107 throw invalid_argument("Error: Invalid day (1-28|29|30|31)!");
108 }
109}
110
111// Print this instance in the format "xxxday, d mmm yyyy".
112void Date::print() const {
113 cout << STR_DAYS[getDayOfWeek(year, month, day)] << ", "
114 << day << " " << STR_MONTHS[month-1] << " " << year << endl;
115}
116
117// Increment this instance to the next day and return this instance by reference
118Date& Date::nextDay() {
119 int lastDayOfMonth = DAYS_IN_MONTHS[month-1];
120 if (month == 2 && isLeapYear(year)) {
121 lastDayOfMonth = 29;
122 }
123
124 // check day against the end of month
125 if (++day > lastDayOfMonth) {
126 day = 1;
127 if (++month > 12) {
128 month = 1;
129 if (++year > YEAR_MAX) {
130 throw out_of_range("Error: Next day is out of range!");
131 }
132 }
133 }
134 return *this;
135}
136
137// Decrement this instance to the previous day and return this instance by reference
138Date& Date::previousDay() {
139 int lastDayOfMonth = DAYS_IN_MONTHS[month-1];
140 if (month == 2 && isLeapYear(year)) {
141 lastDayOfMonth = 29;
142 }
143
144 // check day against the end of month
145 if (--day < 1) {
146 day = lastDayOfMonth;
147 if (--month < 1) {
148 month = 12;
149 if (--year < YEAR_MIN) {
150 throw out_of_range("Error: Previous day is out of range!");
151 }
152 }
153 }
154 return *this;
155}
156
157// Increment this instance to the next month and return this instance by reference
158Date& Date::nextMonth() {
159 if (++month > 12) {
160 month = 1;
161 if (++year > YEAR_MAX) {
162 throw out_of_range("Error: Next month is out of range!");
163 }
164 }
165 // may need to adjust the last day of the month
166 int lastDayOfMonth = DAYS_IN_MONTHS[month-1];
167 if (month == 2 && isLeapYear(year)) {
168 lastDayOfMonth = 29;
169 }
170 if (day > lastDayOfMonth) {
171 day = lastDayOfMonth;
172 }
173 return *this;
174}
175
176// Decrement this instance to the previous month and return this instance by reference
177Date& Date::previousMonth() {
178 if (--month < 1) {
179 month = 12;
180 if (--year < YEAR_MIN) {
181 throw out_of_range("Error: Previous month is out of range!");
182 }
183 }
184 // may need to adjust the last day of the month
185 int lastDayOfMonth = DAYS_IN_MONTHS[month-1];
186 if (month == 2 && isLeapYear(year)) {
187 lastDayOfMonth = 29;
188 }
189 if (day > lastDayOfMonth) {
190 day = lastDayOfMonth;
191 }
192 return *this;
193}
194
195// Increment this instance to the next year and return this instance by reference
196Date& Date::nextYear() {
197 if (++year > YEAR_MAX) {
198 throw out_of_range("Error: Next year is out of range!");
199 }
200 // may need to adjust the last day of the month for leap year (29 Feb)
201 // to non-leap year (28 Feb)
202 if (month == 2 && day == 29 && !isLeapYear(year)) {
203 day = 28;
204 }
205 return *this;
206}
207
208// Decrement this instance to the previous year and return this instance by reference
209Date& Date::previousYear() {
210 if (--year < YEAR_MIN) {
211 throw out_of_range("Error: Previous year is out of range!");
212 }
213 // may need to adjust the last day of the month for leap year (29 Feb)
214 // to non-leap year (28 Feb)
215 if (month == 2 && day == 29 && !isLeapYear(year)) {
216 day = 28;
217 }
218 return *this;
219}
TestDate.cpp
1/* Test Driver Program (TestDate.cpp) */
2#include <iostream>
3#include <stdexcept>
4#include "Date.h"
5
6int main() {
7 Date d1(2012, 1, 1);
8 d1.print(); // Sunday, 1 Jan 2012
9 d1.nextDay().print(); // Monday, 2 Jan 2012
10 d1.print(); // Monday, 2 Jan 2012
11
12 d1.setDate(2012, 1, 31);
13 d1.print(); // Tuesday, 31 Jan 2012
14 d1.nextDay().print(); // Wednesday, 1 Feb 2012
15
16 d1.setDate(2012, 2, 28);
17 d1.print(); // Tuesday, 28 Feb 2012
18 d1.nextDay().print(); // Wednesday, 29 Feb 2012
19
20 d1.setDate(2012, 12, 31);
21 d1.print(); // Monday, 31 Dec 2012
22 d1.nextDay().print(); // Tuesday, 1 Jan 2013
23
24// Date d2(2011, 2, 29); // abrupt termination!
25// d2.print();
26
27 try { // graceful handling of exception
28 Date d3(2011, 2, 29);
29 d3.print();
30 } catch (invalid_argument &ex) {
31 cout << ex.what() << endl; // Error: Invalid day (1-28|29|30|31)!
32 }
33 cout << "Next Statement after try-catch" << endl;
34
35 try { // graceful handling of exception
36 Date d4(9999, 12, 30);
37 d4.nextDay().print(); // Friday, 31 Dec 9999
38 d4.nextDay();
39 d4.print();
40 } catch (out_of_range &ex) {
41 cout << ex.what() << endl; // Error: Next day is outside the valid range!
42 }
43
44 Date d5(2012, 1, 1);
45 d5.previousDay().print(); // Saturday, 31 Dec 2011
46
47 Date d6(2012, 3, 31);
48 d6.nextMonth().print(); // Monday, 30 Apr 2012
49
50 Date d7(2012, 3, 31);
51 d7.previousMonth().print(); // Wednesday, 29 Feb 2012
52
53 Date d8(2012, 2, 29);
54 d8.nextYear().print(); // Thursday, 28 Feb 2013
55
56 Date d9(2012, 2, 29);
57 d9.previousYear().print(); // Monday, 28 Feb 2011
58}
评论