下面是一个运算符重载的事例:
#include "iostream"
using namespace std;
class Time {
private:
int hours;
int minutes;
public:
Time() {
hours = minutes = 0;
}
Time(int h, int m = 0) {
hours = h;
minutes = m;
}
void AddMin(int m) {
minutes += m;
hours += minutes / 60;
minutes %= 60;
}
void AddHr(int h) {
hours += h;
}
void Reset(int h = 0, int m = 0) {
hours = h;
minutes = m;
}
Time Sum(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 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 operator*(double m) const {
Time result;
long totalminutes = hours * m * 60 + minutes * m;
result.hours = totalminutes / 60;
result.minutes = totalminutes % 60;
return result;
}
void Show() const {
cout << hours << " hours, " << minutes << " minutes"<< endl;
}
};
int main() {
Time coding(2, 40);
Time fixing(5, 55);
Time total;
total = coding + fixing;
//total.Show();
//total = coding.operator+(fixing);
total.Show();
return 0;
}
将参数声明为引用的目的是为了提高效率。如果按值传递Time对象,代码的功能将相同,但传递引用,速度将更快,使用的内存将更少。
创建友元函数的第一步是将其原型放在类声明中,并在原型声明前加上关键字friend:
friend Time operator*(double m, const Time& t);
这意味着下面两点:
虽然operator*()函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
虽然operator*()函数不是成员函数,但它与成员函数的访问权限相同。
第二部是编写函数定义。因为它不是成员函数,所以不要使用Time::限定符。另外,不要在定义中使用friend,定义应该如下:
Time operator*(double m, const Time& t) {
Time result;
long totalminutes = t.hours * m * 60 + t.minutes * m;
result.hours = totalminutes / 60;
result.minutes = totalminutes % 60;
return result;
}
实际上,按下面的方式对定义进行修改(交换乘法操作数的顺序),可以将这个友元函数编写为非友元函数:
Time operator*(double m, const Time & t)
{
return t * m;
}
很奇怪,当成员函数operator*() 去掉后面的const时,加上上面的函数定义,编译无法通过。原因还未找到。
重载<<运算符
ostream& operator<<(ostream& os, const Time& t) {
os << t.hours << " hours, " << t.minutes << " minutes";
return os;
}
friend ostream& operator<<(ostream& os, const Time& t);
ostream类将operator<<()函数实现返回一个指向ostream对象的引用。
class Stonewt {
private:
enum{Lbs_per_stn = 14};
int stone;
double pds_left;
double pounds;
public:
Stonewt(double lbs) {
stone = int(lbs) / Lbs_per_stn;
pds_left = (int)(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
Stonewt(int stn, double lbs) {
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
Stonewt() {
stone = pounds = pds_left = 0;
}
~Stonewt() {
}
void show_lbs() const {
cout << stone << " stone, " << pds_left << " pounds\n";
}
void show_stn() const {
cout << pounds << " pounds\n";
}
};
在C++中,接收一个参数的构造函数为将类型与该参数相同的值转换为类提供了蓝图。
Stonewt(double lbs);
Stonewt myCat;
myCat = 19.6;
程序将使用构造函数Stonewt(double)来创建一个临时的Stonewt对象,并将19.6作为初始化值,随后采用逐成员赋值方式将该临时对象的内容复制到myCat中,这一过程称为隐式转换,因为它是自动进行的,而不需要显示强制类型转换。
然而,当程序员拥有更丰富的C++经验时,将发现这种自动特性并非总是合乎需要的,因为这会导致意外的类型转换。因此,C++新增了关键字explicit,用于关闭这种自动特性。
explicit Stonewt(double lbs);
Stonewt myCat;
mycat = 19.6; // no ok
mycat = Stonewt(19.6) //ok
mycat = (Stonewt) 19.6 //ok
是否可以将Stonewt对象转换为double值。要转化typename类型,需要使用这种形式的转换函数:
operator typename();
- 转换函数必须是类方法;
- 转换函数不能指定返回类型;
- 转换函数不能有参数;
operator int() const {
return int(pounds + 0.5);
}
operator double() const {
return pounds;
}