一, 前言
其实本人学习 C++ 的目的, 只是为了体会 OOP 设计思想, 并为利用 System Verilog 验证复杂设计做准备. 如果想要真正做点软件方面项目级的东西, 还需要掌握其他高级语言和库, 框架等知识. 因此该系列博文仅注重语言基础和设计思想. 上一篇该系列博文讲述了 C++ 中基本的类封装, 这次利用运算符重载友元函数来体会下 C++ 的灵活性.
二, 运算符重载友元函数
本文同样以《C++ Primer Plus》中的一个简单示例来讲解此内容. 场景如下: 时间粗劣地分为时和分两部分. 需要完成两个时间的相加, 时间与倍数的相乘 (这个操作不太恰当, 凑活看吧) 以及显示时间操作. 先上代码:
类声明:
- #ifndef MYTIME_H_
- #define MYTIME_H_
- using std::ostream;
- class Time
- {
- private:
- int hours;
- int minutes;
- public:
- Time();
- Time(int h,int m=0);
- void Reset(int h = 0,int m = 0);
- Time operator+(const Time& t) const;
- Time operator*(double mult) const;// 成员函数
- friend Time operator*(double m,const Time& t) // 友元函数(inline)
- {return t * m;}
- friend ostream& operator<<(ostream & os,const Time& t);//<<左侧必须是 ostream 对象 返回 ostream&
- };
- #endif
- mytime.h
类方法定义:
- #include <iostream>
- #include "mytime.h"
- Time::Time()
- {
- hours = minutes = 0;
- }
- Time::Time(int h,int m)
- {
- hours = h;
- minutes = m;
- }
- void Time::Reset(int h,int m)
- {
- hours = h;
- minutes = m;
- }
- Time Time::operator+(const Time& t) const
- {
- Time sum;
- sum.minutes = minutes + t.minutes;
- sum.hours = hours +t.hours +sum.minutes / 60;
- sum.minutes %= 60;
- return sum;
- }
- Time Time::operator*(double mult) const
- {
- Time result;
- long totalminutes = hours * mult * 60 + minutes * mult;
- result.hours = totalminutes / 60;
- result.minutes = totalminutes % 60;
- return result;
- }
- ostream& operator<<(ostream& os,const Time& t)
- {
- os <<t.hours << "hours," << t.minutes << "minutes";
- return os;
- }
- mytime.cpp
以上代码的设计原则是: 想让 Time 类对象的相加, 与常数相乘以及打印操作与 C++ 内置类型一致. 因此 +,*,<<三个符号必须进行运算符重载操作, 即对此类对象使用这三个运算符时的具体实现细节需重新定义. 声明格式为:<返回值类型> operator<op>(). 但是这里存在一个问题, 成员函数 Time operator*(double mult) 在被调用时, 类对象必须放置在 * 符号左侧, 也就是说当表达式为 m*t(t 为 Time 类对象)时, 编译器会报错. 使用<<运算符打印 Time 类对象时同样会遇到此问题.
为了实现用户友好, 使用没有此限制的友元函数重载运算符是个不错的选择. 友元函数是类接口的扩展, 这类函数虽然不是类成员函数, 但可以访问类私有成员. 需要注意的一点是:<<输出数据时, 左侧必须是 ostream 类对象. 因此重载<<运算符时, 必须使函数返回参数中 ostream 类对象本身才能正确编译 cout <<A << B; 语句. 这条语句与(cout << A) << B; 等同.
三, 应用程序及结果分析
应用程序示例代码:
- #include <iostream>
- #include "mytime.h"
- using std::endl;
- int main()
- {
- using std::cout;
- Time planning;
- Time coding(2,40);
- Time fixing(5,55);
- Time total;
- Time adjusted1,adjusted2;
- cout << "planning time =";
- cout << planning << endl;
- cout << "coding time =";
- cout << coding << endl;
- cout << "fixing time =";
- cout << fixing << endl;
- cout << endl;
- total = coding + fixing;
- cout << "coding + fixing =";
- cout << total << endl;
- adjusted1 = total * 1.5;// 调用成员函数
- cout << "total * 1.5 =";
- cout << adjusted1 << endl;
- adjusted2 = 1.5 * total;// 调用友元函数
- cout << "1.5 * total =";
- cout << adjusted2 << endl;
- }
- usetime.cpp
Time 类对象 planning 创建时隐式调用用户定义默认构造函数, 而 coding 和 fixing 因有参数传递调用第二个构造函数, 这正是 C++ 的多态性质. 可以看到, 打印 Time 类对象与打印 C++ 内置类型对象无异. 重点关注 "*" 运算符的使用, adjusted1 和 adjusted2 表达式中乘法运算依次调用了成员函数和友元函数. C++ 编译器同样会自动识别用户的意图. 打印结果如图:
应用程序运行正确, 重载的两个 Time 类对象的加法运算和 Time 类对象与常数的乘法运算结果无误. 之后的两篇博客依次讲述动态内存分配与类继承内容, 有错误的地方欢迎指正.
来源: https://www.cnblogs.com/moluoqishi/p/10729034.html