• 类与对象(下篇)


    1.日期类的完整实现

    1. //Date.h
    2. #pragma once
    3. #include
    4. #include
    5. using namespace std;
    6. // 一个到底可以重载哪些运算符?-》哪些运算符对这个类型有意义
    7. class Date
    8. {
    9. // 友元函数 -- 这个函数内部可以使用Date对象访问私有保护成员
    10. friend ostream& operator<<(ostream& out, const Date& d);
    11. friend istream& operator>>(istream& in, Date& d);
    12. public:
    13. // 获取某年某月的天数
    14. // 会频繁调用,所以直接放在类里面定义作为inline
    15. int GetMonthDay(int year, int month)
    16. {
    17. static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    18. int day = days[month];
    19. if (month == 2
    20. && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
    21. {
    22. day += 1;
    23. }
    24. return day;
    25. }
    26. bool CheckDate()
    27. {
    28. if (_year >= 1
    29. && _month > 0 && _month < 13
    30. && _day > 0 && _day <= GetMonthDay(_year, _month))
    31. {
    32. return true;
    33. }
    34. else
    35. {
    36. return false;
    37. }
    38. }
    39. // 构造会频繁调用,所以直接放在类里面定义作为inline
    40. Date(int year = 1, int month = 1, int day = 1)
    41. {
    42. _year = year;
    43. _month = month;
    44. _day = day;
    45. /*if (!CheckDate())
    46. {
    47. Print();
    48. cout << "刚构造的日期非法" << endl;
    49. }*/
    50. assert(CheckDate());
    51. }
    52. void Print() const;
    53. bool operator==(const Date& d) const;
    54. bool operator!=(const Date& d) const;
    55. bool operator>(const Date& d) const;
    56. bool operator>=(const Date& d) const;
    57. bool operator<(const Date& d) const;
    58. bool operator<=(const Date& d) const;
    59. Date operator+(int day) const;
    60. Date& operator+=(int day);
    61. // ++d1;
    62. // d1++;
    63. // 直接按特性重载,无法区分
    64. // 特殊处理,使用重载区分,后置++重载增加一个int参数跟前置构成函数重载进行区分
    65. Date& operator++(); // 前置
    66. Date operator++(int); // 后置
    67. // d1 - 100
    68. Date operator-(int day) const;
    69. Date& operator-=(int day);
    70. Date& operator--(); // 前置
    71. Date operator--(int); // 后置
    72. // d1 - d2
    73. int operator-(const Date& d) const;
    74. //void operator<<(ostream& out);
    75. private:
    76. int _year;
    77. int _month;
    78. int _day;
    79. };
    80. // 流插入重载
    81. inline ostream& operator<<(ostream& out, const Date& d)
    82. {
    83. out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
    84. return out;
    85. }
    86. // 流提取重载
    87. inline istream& operator>>(istream& in, Date& d)
    88. {
    89. in >> d._year >> d._month >> d._day;
    90. assert(d.CheckDate());
    91. return in;
    92. }
    1. //Date.cpp
    2. #include "Date.h"
    3. // const int* const ptr;
    4. // void Date::Print(const Date* const this)
    5. void Date::Print() const
    6. {
    7. //_year = 1;
    8. cout << _year << "/" << _month << "/" << _day << endl;
    9. }
    10. // 任何一个类,只需要写一个> == 或者 < ==重载 剩下比较运算符重载复用即可
    11. bool Date::operator== (const Date& d) const
    12. {
    13. return _year == d._year
    14. && _month == d._month
    15. && _day == d._day;
    16. }
    17. // d1 != d2
    18. bool Date::operator!=(const Date& d) const
    19. {
    20. return !(*this == d);
    21. }
    22. // d1 > d2
    23. bool Date::operator>(const Date& d) const
    24. {
    25. if ((_year > d._year)
    26. || (_year == d._year && _month > d._month)
    27. || (_year == d._year && _month == d._month && _day > d._day))
    28. {
    29. return true;
    30. }
    31. else
    32. {
    33. return false;
    34. }
    35. }
    36. bool Date::operator>=(const Date& d) const
    37. {
    38. return (*this > d) || (*this == d);
    39. }
    40. bool Date::operator<(const Date& d) const
    41. {
    42. return !(*this >= d);
    43. }
    44. bool Date::operator<=(const Date& d) const
    45. {
    46. return !(*this > d);
    47. }
    48. // d1 + 100
    49. Date Date::operator+(int day) const
    50. {
    51. //Date ret(*this);
    52. Date ret = *this;
    53. ret += day;
    54. return ret;
    55. }
    56. // d2 += d1 += 100
    57. Date& Date::operator+=(int day)
    58. {
    59. if (day < 0)
    60. {
    61. return *this -= -day;
    62. }
    63. _day += day;
    64. while (_day > GetMonthDay(_year, _month))
    65. {
    66. _day -= GetMonthDay(_year, _month);
    67. ++_month;
    68. if (_month == 13)
    69. {
    70. _year++;
    71. _month = 1;
    72. }
    73. }
    74. return *this;
    75. }
    76. //Date Date::operator+(int day)
    77. //{
    78. // Date ret = *this;
    79. // // ...
    80. // ret._day += day;
    81. // while (ret._day > GetMonthDay(ret._year, ret._month))
    82. // {
    83. // //...
    84. // }
    85. //
    86. // return ret;
    87. //}
    88. //
    89. d1 += 100
    90. //Date& Date::operator+=(int day)
    91. //{
    92. // *this = *this + day;
    93. //
    94. // return *this;
    95. //}
    96. Date& Date::operator++() // 前置
    97. {
    98. //*this += 1;
    99. //return *this;
    100. return *this += 1;
    101. }
    102. Date Date::operator++(int) // 后置
    103. {
    104. Date tmp(*this);
    105. *this += 1;
    106. return tmp;
    107. }
    108. Date Date::operator-(int day) const
    109. {
    110. Date ret = *this;
    111. ret -= day;
    112. return ret;
    113. }
    114. Date& Date::operator-=(int day)
    115. {
    116. if (day < 0)
    117. {
    118. return *this += -day;
    119. }
    120. _day -= day;
    121. while (_day <= 0)
    122. {
    123. --_month;
    124. if (_month == 0)
    125. {
    126. --_year;
    127. _month = 12;
    128. }
    129. _day += GetMonthDay(_year, _month);
    130. }
    131. return *this;
    132. }
    133. Date& Date::operator--() // 前置
    134. {
    135. return *this -= 1;
    136. }
    137. Date Date::operator--(int) // 后置
    138. {
    139. Date tmp(*this);
    140. *this -= 1;
    141. return tmp;
    142. }
    143. // d1 - d2
    144. int Date::operator-(const Date& d) const
    145. {
    146. int flag = 1;
    147. Date max = *this;
    148. Date min = d;
    149. if (*this < d)
    150. {
    151. max = d;
    152. min = *this;
    153. flag = -1;
    154. }
    155. int n = 0;
    156. while (min != max)
    157. {
    158. ++min;
    159. ++n;
    160. }
    161. return n * flag;
    162. }
    163. //void Date::operator<<(ostream& out)
    164. //{
    165. // out << _year << "-" << _month << "-" << _day << endl;
    166. //}
    1. //Test.cpp
    2. #include "Date.h"
    3. //class A
    4. //{
    5. //public:
    6. // A(int a = 0)
    7. // {
    8. // _a = a;
    9. // cout << "A(int a = 0)->" <<_a<< endl;
    10. // }
    11. //
    12. // ~A()
    13. // {
    14. // cout << "~A()->" <<_a<
    15. // }
    16. //private:
    17. // int _a;
    18. //};
    19. //
    20. //A aa3(3);
    21. //
    22. //void f()
    23. //{
    24. // static int i = 0;
    25. // static A aa0(0);
    26. // A aa1(1);
    27. // A aa2(2);
    28. // static A aa4(4);
    29. //}
    30. //
    31. 构造顺序:3 0 1 2 4 1 2
    32. 析构顺序:~2 ~1 ~2 ~1 ~4 ~0 ~3
    33. //int main()
    34. //{
    35. // f();
    36. // f();
    37. //
    38. // return 0;
    39. //}
    40. //class A
    41. //{
    42. //public:
    43. // A(int a = 0)
    44. // {
    45. // _a = a;
    46. // cout << "A(int a = 0)->" << _a << endl;
    47. // }
    48. //
    49. // // A aa2(aa1);
    50. // A(const A& aa)
    51. // {
    52. // _a = aa._a;
    53. // cout << "A(const A& aa)->" << _a << endl;
    54. // }
    55. //
    56. // ~A()
    57. // {
    58. // cout << "~A()->" << _a << endl;
    59. // }
    60. //private:
    61. // int _a;
    62. //};
    63. //
    64. //void func1(A aa)
    65. //{
    66. //
    67. //}
    68. //
    69. //void func2(A& aa)
    70. //{
    71. //
    72. //}
    73. //
    74. //A func3()
    75. //{
    76. // static A aa(3);
    77. // return aa;
    78. //}
    79. //
    80. //A& func4()
    81. //{
    82. // static A aa(4);
    83. // return aa;
    84. //}
    85. //
    86. //int main()
    87. //{
    88. // //A aa1(1);
    89. // //A aa2(aa1);
    90. //
    91. // //func1(aa1);
    92. // //func2(aa1);
    93. // func3();
    94. // cout << endl << endl;
    95. // func4();
    96. //
    97. // //int i = 0;
    98. // //int& j = i;
    99. // //cout << typeid(j).name() << endl;
    100. //
    101. // return 0;
    102. //}
    103. //#pragma once
    104. //
    105. //class Time
    106. //{
    107. //public:
    108. // Time()
    109. // {
    110. // _hour = 1;
    111. // _minute = 1;
    112. // _second = 1;
    113. // }
    114. //
    115. // Time& operator=(const Time& t)
    116. // {
    117. // cout << "Time& operator=(const Time& t)" << endl;
    118. // if (this != &t)
    119. // {
    120. // _hour = t._hour;
    121. // _minute = t._minute;
    122. // _second = t._second;
    123. // }
    124. //
    125. // return *this;
    126. // }
    127. //private:
    128. // int _hour;
    129. // int _minute;
    130. // int _second;
    131. //};
    132. //
    133. //class Date
    134. //{
    135. //public:
    136. // // 构造会频繁调用,所以直接放在类里面定义作为inline
    137. // Date(int year = 1, int month = 1, int day = 1)
    138. // {
    139. // _year = year;
    140. // _month = month;
    141. // _day = day;
    142. // }
    143. //
    144. // Date(const Date& d)
    145. // {
    146. // cout << "Date(const Date& d)" << endl;
    147. // _year = d._year;
    148. // _month = d._month;
    149. // _day = d._day;
    150. // }
    151. //
    152. // // d1 = d3;
    153. // // d2 = d2;
    154. // //Date& operator=(const Date& d)
    155. // Date operator=(const Date d)
    156. // //{
    157. // // if (this != &d)
    158. // // {
    159. // // _year = d._year;
    160. // // _month = d._month;
    161. // // _day = d._day;
    162. // // }
    163. //
    164. // // return *this;
    165. // //}
    166. //
    167. //private:
    168. // int _year;
    169. // int _month;
    170. // int _day;
    171. //
    172. // // 自定义类型
    173. // Time _t;
    174. //};
    175. //
    176. //
    177. 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
    178. //typedef int DataType;
    179. //class Stack
    180. //{
    181. //public:
    182. // Stack(size_t capacity = 10)
    183. // {
    184. // _array = (DataType*)malloc(capacity * sizeof(DataType));
    185. // if (nullptr == _array)
    186. // {
    187. // perror("malloc申请空间失败");
    188. // return;
    189. // }
    190. //
    191. // _size = 0;
    192. // _capacity = capacity;
    193. // }
    194. //
    195. // void Push(const DataType& data)
    196. // {
    197. // // CheckCapacity();
    198. // _array[_size] = data;
    199. // _size++;
    200. // }
    201. //
    202. // ~Stack()
    203. // {
    204. // if (_array)
    205. // {
    206. // free(_array);
    207. // _array = nullptr;
    208. // _capacity = 0;
    209. // _size = 0;
    210. // }
    211. // }
    212. //
    213. //private:
    214. // DataType *_array;
    215. // size_t _size;
    216. // size_t _capacity;
    217. //};
    218. //
    219. 躺赢 -- 构造、拷贝构造、赋值重载、析构默认生成都可以用
    220. //class MyQueue
    221. //{
    222. //private:
    223. // Stack _st1;
    224. // Stack _st2;
    225. //};
    226. //
    227. //void Test()
    228. //{
    229. // Date d1(2022, 7, 24);
    230. // Date d2(d1);
    231. //
    232. // Date d3(2022, 8, 24);
    233. // d2 = d1 = d3; // d1.operator=(&d1, d3)
    234. // d2 = d2;
    235. //
    236. // Stack st1;
    237. // Stack st2;
    238. // st2.Push(1);
    239. // st2.Push(2);
    240. // st1 = st2; // 实现深拷贝赋值解决
    241. //
    242. // int i = 0, j = 1, k = 2;
    243. // k = i = j = 10;
    244. //}
    245. void TestDate1()
    246. {
    247. Date d1(2022, 7, 24);
    248. Date d2(2022, 7, 25);
    249. Date d3(2021, 7, 25);
    250. cout << (d1 < d2) << endl;
    251. cout << (d1 < d3) << endl;
    252. cout << (d1 == d3) << endl;
    253. cout << (d1 > d3) << endl;
    254. }
    255. void TestDate2()
    256. {
    257. //Date d1(2022, 7, 24);
    258. //d1 += 4;
    259. //d1.Print();
    260. //d1 += 40; // 跨月
    261. //d1.Print();
    262. //d1 += 400;// 跨年
    263. //d1.Print();
    264. //d1 += 4000; // 跨闰年
    265. //d1.Print();
    266. Date d1(2022, 7, 24);
    267. /*Date d2 = d1 + 4;
    268. d2.Print();*/
    269. (d1 + 4).Print();
    270. (d1 + 40).Print();// 跨月
    271. (d1 + 400).Print();// 跨年
    272. (d1 + 4000).Print(); // 跨闰年
    273. (d1 + 40000).Print();
    274. Date ret1 = ++d1; // d1.operator++(&d1)
    275. Date ret2 = d1++; // d1.operator++(&d2, 0)
    276. }
    277. void TestDate3()
    278. {
    279. Date d1(2022, 7, 25);
    280. (d1 - 4).Print();
    281. (d1 - 40).Print();// 跨月
    282. (d1 - 400).Print();// 跨年
    283. (d1 - 4000).Print(); // 跨闰年
    284. (d1 - 40000).Print();
    285. Date d2(2022, 7, 25);
    286. Date d3(2023, 2, 15);
    287. cout << d2 - d3 << endl;
    288. cout << d3 - d2 << endl;
    289. Date d4(2000, 2, 15);
    290. cout << d2 - d4 << endl;
    291. cout << d4 - d2 << endl;
    292. }
    293. void TestDate4()
    294. {
    295. /*Date d1(2022, 7, 32);
    296. d1.Print();
    297. Date d2(2022, 2, 29);
    298. d2.Print();
    299. d2++;
    300. d2.Print();*/
    301. Date d1(2022, 7, 25);
    302. Date d2(2022, 7, 26);
    303. cout << d1 << d2;
    304. cin >> d1 >> d2;
    305. cout << d1 << d2;
    306. //d1.operator<<(cout);
    307. //d1 << cout;
    308. //cout << (d1 + 100);
    309. //(d1 + 100).Print();
    310. //(d1 + -100).Print();
    311. }
    312. void TestDate5()
    313. {
    314. const char* WeeDayToStr[] = { "周一", "周二", "周三", "周四", "周五", "周六", "周天" };
    315. Date d1, d2;
    316. int day = 0;
    317. int option = 0;
    318. do {
    319. cout << "*******************************" << endl;
    320. cout << " 1、日期加/减天数 2、日期减日期" << endl;
    321. cout << " 3、日期->周几 -1、退出" << endl;
    322. cout << "*******************************" << endl;
    323. cout << "请选择:>";
    324. cin >> option;
    325. if (option == 1)
    326. {
    327. cout << "请依次输入日期及天数(减天数就输入负数):";
    328. cin >> d1 >> day;
    329. cout << "日期加减天数后的日期:" << d1 + day << endl;
    330. }
    331. else if (option == 2)
    332. {
    333. cout << "请依次输入两个日期:";
    334. cin >> d1 >> d2;
    335. cout << "相差的天数:" << d1 - d2 << endl;
    336. }
    337. else if (option == 3)
    338. {
    339. cout << "请输入日期:";
    340. cin >> d1;
    341. Date start(1, 1, 1);
    342. int n = d1 - start;
    343. int weekDay = 0; // 周一
    344. weekDay += n;
    345. //weekDay += 9;
    346. //cout << "周" << weekDay % 7 + 1 << endl;
    347. cout << WeeDayToStr[weekDay % 7] << endl;
    348. }
    349. else
    350. {
    351. cout << "无此选项,请重新选择" << endl;
    352. }
    353. } while (option != -1);
    354. }
    355. void TestDate6()
    356. {
    357. Date d1(2022, 7, 25);
    358. const Date d2(2022, 7, 25);
    359. d1.Print();
    360. d2.Print();
    361. d1 < d2;
    362. d2 < d1;
    363. }
    364. //int main()
    365. //{
    366. // //TestDate6();
    367. //
    368. // //int i = 0;
    369. // //double d = 1.1;
    370. // //cout << i; // cout.operator<<(i);
    371. // //cout << d; // cout.operator<<(d);
    372. //
    373. // return 0;
    374. //}
    375. class A
    376. {
    377. public:
    378. // 他们是默认成员函数,我们不写编译器会自动生成,自动生成就够用了,所以一般是不需要我们自己写的
    379. // 特殊场景:不想让别人取到这个类型对象的地址
    380. A* operator&()
    381. {
    382. return nullptr;
    383. }
    384. const A* operator&()const
    385. {
    386. return nullptr;
    387. }
    388. void Print() const
    389. {
    390. //_year = 1;
    391. cout << _year << "/" << _month << "/" << _day << endl;
    392. }
    393. /*void Print()
    394. {
    395. _year = 1;
    396. cout << _year << "/" << _month << "/" << _day << endl;
    397. }*/
    398. private:
    399. int _year; // 年
    400. int _month; // 月
    401. int _day; // 日
    402. };
    403. int main()
    404. {
    405. A d1;
    406. const A d2;
    407. d1.Print();
    408. d2.Print();
    409. cout << &d1 << endl;
    410. cout << &d2 << endl;
    411. return 0;
    412. }

    2.const成员

          将 const 修饰的 成员函数 称之为 const 成员函数 const 修饰类成员函数,实际修饰该成员函数 隐含的 this 指针 ,表明在该成员函数中 不能对类的任何成员进行修改。

    3.取地址及const取地址操作符重载 

          这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
    1. class Date
    2. {
    3. public :
    4. Date* operator&()
    5. {
    6. return this ;
    7. }
    8. const Date* operator&()const
    9. {
    10. return this ;
    11. }
    12. private :
    13. int _year ; // 年
    14. int _month ; // 月
    15. int _day ; // 日
    16. };
          这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要 重载,比如想让别人获取到指定的内容!

    4. 再谈构造函数

    4.1 构造函数体赋值

          在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
    1. class Date
    2. {
    3. public:
    4. Date(int year, int month, int day)
    5. {
    6. _year = year;
    7. _month = month;
    8. _day = day;
    9. }
    10. private:
    11. int _year;
    12. int _month;
    13. int _day;
    14. };
          虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化, 构造函数体中的语句只能将其称为赋初值 ,而不能称作初始化。因为 初始化只能初始化一次,而构造函数体 内可以多次赋值

    4.2 初始化列表

         初始化列表:以一个 冒号开始 ,接着是一个以 逗号分隔的数据成员列表 ,每个 " 成员变量 " 后面跟一个 放在括 号中的初始值或表达式。
    1. class Date
    2. {
    3. public:
    4. Date(int year, int month, int day)
    5. : _year(year)
    6. , _month(month)
    7. , _day(day)
    8. {}
    9. private:
    10. int _year;
    11. int _month;
    12. int _day;
    13. };
       【注意】
    1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)。
    2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
      • 引用成员变量
      • const 成员变量
      • 自定义类型成员 ( 且该类没有默认构造函数时 )
    3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
    4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。

    4.3 explicit关键字

          构造函数不仅可以构造与初始化对象, 对于单个参数或者除第一个参数无默认值其余均有默认值的构造函 数,还具有类型转换的作用
    1. class Date
    2. {
    3. public:
    4. // 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
    5. // explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译
    6. explicit Date(int year)
    7. :_year(year)
    8. {}
    9. /*
    10. // 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具有类型转
    11. 换作用
    12. // explicit修饰构造函数,禁止类型转换
    13. explicit Date(int year, int month = 1, int day = 1)
    14. : _year(year)
    15. , _month(month)
    16. , _day(day)
    17. {}
    18. */
    19. Date& operator=(const Date& d)
    20. {
    21. if (this != &d)
    22. {
    23. _year = d._year;
    24. _month = d._month;
    25. _day = d._day;
    26. }
    27. return *this;
    28. }
    29. private:
    30. int _year;
    31. int _month;
    32. int _day;
    33. };
    34. void Test()
    35. {
    36. Date d1(2022);
    37. // 用一个整形变量给日期类型对象赋值
    38. // 实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值
    39. d1 = 2023;
    40. // 将1屏蔽掉,2放开时则编译失败,因为explicit修饰构造函数,禁止了单参构造函数类型转换的作用
    41. }
         上述代码可读性不是很好, explicit 修饰构造函数,将会禁止构造函数的隐式转换

    5. static成员

    5.1 概念

          声明为 static 的类成员 称为 类的静态成员 ,用 static 修饰的 成员变量 ,称之为 静态成员变量 ;用 static 修饰 成员函数 ,称之为 静态成员函数 静态成员变量一定要在类外进行初始化。
    1. class A
    2. {
    3. public:
    4. A()
    5. {
    6. ++_scount;
    7. }
    8. A(const A& t)
    9. {
    10. ++_scount;
    11. }
    12. ~A()
    13. {
    14. --_scount;
    15. }
    16. //静态成员函数 -- 没有this指针
    17. static int GetACount()
    18. {
    19. return _scount;
    20. }
    21. private:
    22. static int _scount; //声明
    23. };
    24. //类外面定义初始化
    25. int A::_scount = 0;
    26. void TestA()
    27. {
    28. cout << A::GetACount() << endl;
    29. A a1, a2;
    30. A a3(a1);
    31. cout << A::GetACount() << endl;
    32. }

    5.2 特性

    • 静态成员所有类对象所共享,不属于某个具体的对象,存放在静态区;
    • 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
    • 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
    • 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
    • 静态成员也是类的成员,受publicprotectedprivate 访问限定符的限制。

    6. 友元

          友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
          友元分为: 友元函数 友元类。

    6.1 友元函数

         问题:现在尝试去重载 operator<< ,然后发现没办法将 operator<< 重载成成员函数。 因为 cout 的输出流对 象和隐含的 this 指针在抢占第一个参数的位置 this 指针默认是第一个参数也就是左操作数了。但是实际使用中cout 需要是第一个形参对象,才能正常使用。所以要将 operator<< 重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>> 同理。
    1. class Date
    2. {
    3. public:
    4. Date(int year, int month, int day)
    5. : _year(year)
    6. , _month(month)
    7. , _day(day)
    8. {}
    9. // d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
    10. // 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
    11. ostream& operator<<(ostream& _cout)
    12. {
    13. _cout << _year << "-" << _month << "-" << _day << endl;
    14. return _cout;
    15. }
    16. private:
    17. int _year;
    18. int _month;
    19. int _day;
    20. };
         友元函数 可以 直接访问 类的 私有 成员,它是 定义在类外部 普通函数 ,不属于任何类,但需要在类的内部声明,声明时需要加friend 关键字。
    1. class Date
    2. {
    3. friend ostream& operator<<(ostream& _cout, const Date& d);
    4. friend istream& operator>>(istream& _cin, Date& d);
    5. public:
    6. Date(int year = 1900, int month = 1, int day = 1)
    7. : _year(year)
    8. , _month(month)
    9. , _day(day)
    10. {}
    11. private:
    12. int _year;
    13. int _month;
    14. int _day;
    15. };
    16. ostream& operator<<(ostream& _cout, const Date& d) {
    17. _cout << d._year << "-" << d._month << "-" << d._day;
    18. return _cout;
    19. }
    20. istream& operator>>(istream& _cin, Date& d) {
    21. _cin >> d._year;
    22. _cin >> d._month;
    23. _cin >> d._day;
    24. return _cin;
    25. }
    26. int main()
    27. {
    28. Date d;
    29. cin >> d;
    30. cout << d << endl;
    31. return 0;
    32. }
    • 友元函数 可访问类的私有和保护成员,但 不是类的成员函数;
    • 友元函数 不能用 const 修饰;
    • 友元函数 可以在类定义的任何地方声明, 不受类访问限定符限制
    • 一个函数可以是多个类的友元函数;
    • 友元函数的调用与普通函数的调用原理相同。

    6.2 友元类

        友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

    • 友元关系是单向的,不具有交换性。比如上述Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time类的私有成员变量,但想在Time 类中访问 Date 类中私有的成员变量则不行。
    • 友元关系不能传递 。如果B A 的友元, C B 的友元,则不能说明 C A 的友元。
    • 友元关系不能继承。

    7. 内部类

         概念: 如果一个类定义在另一个类的内部,这个内部类就叫做内部类 。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
         
          注意: 内部类就是外部类的友元类 ,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
          特性:
    • 内部类可以定义在外部类的publicprotectedprivate都是可以的。
    • 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
    • sizeof(外部类)=外部类,和内部类没有任何关系。

    8.练习题

           求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

    1. int i = 1;
    2. int sum = 0;
    3. class Sum
    4. {
    5. public:
    6. Sum()
    7. {
    8. sum += i;
    9. ++i;
    10. }
    11. };
    12. class Solution {
    13. public:
    14. int Sum_Solution(int n) {
    15. Sum a[n];//调用n次sum的构造函数
    16. return sum;
    17. }
    18. };

                根据输入的日期,计算是这一年的第几天。保证年份为4位数且日期合法。 

    1. #include
    2. using namespace std;
    3. int main()
    4. {
    5. int year, month, day;
    6. cin >> year >> month >> day;
    7. //2012 12 31
    8. int monthDays1_N[13] = { 0,31,59,90,120,151,181,212,243,273,304,334,365 };
    9. //[1,month-1]
    10. int n = monthDays1_N[month - 1] + day;
    11. if (month > 2 &&( (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
    12. n += 1;
    13. return 0;
    14. }

  • 相关阅读:
    【C++心愿便利店】No.6---C++之拷贝构造函数
    便携式电热水壶外贸出口欧洲CE认证准备资料
    【Spring进阶系列丨第二篇】Spring中的两大核心技术IoC(控制反转)与DI(依赖注入)
    【消息中间件】默认的RocketMQ消息消费者是如何启动的?
    shell脚本中加入这条可以执行完一个脚本回到这个目录下
    ConcurrentHashMap 源码解析
    学习java的第三十三天。。。(XML解析)
    linux查看用户相关信息的命令
    中文编程工具开发语言开发的实际案例:触摸屏点餐软件应用场景实例
    【C语言】【结构体的内存对齐】计算结构体内存大小,有图解
  • 原文地址:https://blog.csdn.net/zhao19971014/article/details/126413787