C++中的操作符重载

首先说句,为什么要使用操作符重载呢?

其实我们使用别人编写好的类时往往不用考虑,你不用查看cout << a; 中<<是如何重载的,就可以自如地在屏幕上输出或在文件中写入字符,字符串,数字,乃至指针地址,可当我们自己设计类给自己或其他程序员使用时就不得不考虑了。

现在假设我设计一个时间类,初始声明代码如下

class Time
{
private:
	int hours;
	int minutes;
public:
	Time(int h = 0, int m = 0);
};

这里就只有两个成员变量和一个构造函数,实际重载时会有以下几种情况:

1、二元操作符的两个参数均为Time类对象:

这时我们有两种选择,第一种就是常见的成员函数实现

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 operator+(const Time &t1, const Time &t2)
{
	Time sum;
	sum.minutes = t1.minutes + t2.minutes;
	sum.hours = t1.hours + t2.hours + sum.minutes/60;
	sum.minutes %= 60;
	return sum;
}

当然,我们要在类声明中添加对应的函数声明,修改类声明代码:

class Time
{
private:
	int hours;
	int minutes;
public:
	Time(int h = 0, int m = 0);
        Time operator+ (const Time & t)const; 
        //friend Time operator+ (const Time & t1, const Time & t2);
};

这里需要注意的就是这两种不能同时定义,否则编译时会有二义性错误,因为当你在其它文件中使用加法时:

Time coding(2,40);
Time fixing(5,55);
Time total;
total = coding + fixing;

编译器将不知道要匹配哪种方法。那么就有人问了,为啥还要有友元函数这种方法呢?是闲着没事做吗?当然不是,我们来看第二种情况。


2、二元操作符的一个参数为Time类对象:

现在呢,其他人给我提供的时间对象是一个double型的变量,单位呢是小时,我需要整合运算,理论上来说只需要重载操作符重载函数即可,也就是加入声明代码:

Time operator+ (double n)const;

以及对应的实现:

Time Time::operator+(double n) const
{
	Time result;
        int i = n;
        n = n - i;

        result.minutes = minutes + n * 60;
        result.hours = hours + i + result.minutes /60;
	result.minutes %= 60;

	return result;
}

到这里,假设有个Time类的实例A,计算A+1.5是没问题的,可计算1.5+A是不行的,因为左边的操作数不是调用对象,这里就需要非成员函数,而且还要能访问类的私有成员,于是友元函数就产生了,它在类中声明,但不是成员函数,但又能访问私有成员。所以还需要在类中声明:

friend Time operator+ (double n, const Time & t);

实现文件中定义:

Time operator+ (double n, const Time & t)
{
	Time result;
        int i = n;
        n = n - i;

        result.minutes = t.minutes + n * 60;
        result.hours = t.hours + i + result.minutes /60;
	result.minutes %= 60;

	return result;
}

当然有更简单的方法:

Time operator+ (double n, const Time & t)
{
    return t * n;
}

这里友元函数和成员函数都需要定义,因为参数顺序不同。

成员函数对应A+1.5,友元函数对应1.5+A。


3、综合使用:

综上,要实现Time类两两相加或加上一个double类型,要2个成员函数和1个友元函数,那有没有简单点的实现呢?

有的,那就是利用类的隐式转换。首先看:

int a = 3.33;

这是可行的,C++将double型的自动转换为int型,假如两种类型互相兼容的话,C++都会自动转换。

那么,当我们在类声明中加入接受一个参数的构造函数时,这个构造函数可以作为转换函数来转换类型。加入声明:

Time (double dhrs);

实现代码:

Time::Time(double dhrs)
{
   int i = dhrs;
   dhrs= dhrs - i;

   hours = i;
   minutes = dhrs * 60;
 }

那么下面的代码是合法的:

Time planning;
planning = 1.5;

程序将使用构造函数Time( double ) 来创建一个临时Time对象,参数即为1.5。随后,采用逐成员赋值的方法将该临时对象的内容复制到planning中。

notes:

当然,这种特性是可以关闭的,当你要防止意外的自动转换时,可以用关键字explicit来关闭该特性,也就是,声明为:

explicit Time (double dhrs);

显式转换则不受影响。使用转换函数还可以将Time对象隐式转换为double型,关于转换函数更详细地可以再单独了解学习。

现在再回过头来看加法的实现,首先将之前的3个函数去掉,在类中声明如下的友元函数:

friend Time operator+ (const Time & t1, const Time & t2);

在实现文件中添加实现代码:

Time operator+ (const Time & t1, const Time & t2)
{
	Time sum;
	sum.minutes = t1.minutes + t2.minutes;
	sum.hours = t1.hours + t2.hours + sum.minutes/60;
	sum.minutes %= 60;
	return sum;
}

这时候就可以实现:

Time A, B;
A + B;
A + 1.5;
1.5 + A;

因为他们被解释为operator+(A, B);    operator+(A, 1.5);    operator+(1.5, A);

在这些函数中参数的double类型被自动隐式转换为Time类,然后运算。


好了,关于操作符重载就说到这里了,完成,如有错误,还望不吝赐教。



猜你喜欢

转载自blog.csdn.net/chrisxiaoniu/article/details/79961022