C++重载运算符


最近突然开始看C++的重载运算符。想到了一些历史遗留问题。

  • 重载[]运算符

    class safearay
    {
       private:
          int arr[SIZE];
       public:
          safearay() 
          {
             for(int i = 0; i < SIZE; i++) arr[i] = i;
          }
          int& operator[](int i) // 为什么是int &  怎么理解?
          {
              return arr[i];
          }
    };
  • 重载<<运算符,实现自己的‘cout’。

    class node
    {
        public:
        const node& operator << (int value) const //这么多const和这里的&是什么意思?
        {
            printf("%d",value);
            return *this;
        }
    }myout;

在此先感谢xzy的鼎力相助!

1. 这里的 & 是什么作用?

学习过指针的同学知道,我们定义一个指针ptr,里面需要存储的是一个地址。我们使用的方法是:
int a=0, *ptr=&a;

*ptr表示定义了一个指针变量,&a 表示取变量 a 的地址。比如0x61fe0c2,0x表示十六进制,整体表示一个32位地址。

但是此处的&用法肯定和上面不同:一个operator 能有什么地址?

不要忘记,我们还有一个地方用到了&

void swap(int &a,int &b)
{
	int tmp;
	tmp=a, a=b, b=tmp;
}
int main()
{	
	int x=1,y=2;
	swap(x,y);
}

在这里,我们交换了xyswap函数的参数为两个“引用值”。
将变量x,y传递至swap函数后,相当于执行了操作:
int &a=x, &b=y;

此处, ab相当于xy的别名。我改变了ab,同时也改变了xy。因而,我们能在函数中实现xy的交换。

如果我们输出ax的地址,我们能发现,他们在内存中的地址是一样的!

也就是说,在内存中,程序不会为a新分配一个空间。

int a=0; int *p = &a; int& b=a;
   cout<<&b<<' '<<&a<<' ';

输出: 0x61fe0c 0x61fe0c

2. 如果能理解引用,我们再回过头看重载运算符。

class node{
	public:	
	int arr[10];
	int& operator[](int i)
	{
		...	
		return arr[i];
	}
}X;
int main()
{
	int a=X[1]+X[2];
	X[1]=4;
	return 0;
}

我们理解一下这里main里的语句。

a=x[1]+x[2],[]已经被重载了,所以程序会返回arr[1]arr[2]
a=X.arr[1]+X.arr[2],没问题。

x[1]=4;当我们执行x[1]这部分时,重载函数就直接返回一个“替身”。这个替身没有名字,替身的主人是X.arr[1]

这样一来,等号左边是一个替身,我们让它等于4,就相当于正在操作X.arr[1]=4

因此,此处的&能够让我们方便地使用赋值操作。如果缺失了&,无法赋值,甚至编译都无法通过。

#include <cstdio>
using namespace std;
class node{
	int arr[10];
    public:
    node() 
    {
        for (int i=0;i<10;i++) arr[i]=i;
    }
    int& operator[](int i)
	{
		return arr[i];
	}
}X;
int main()
{
    int a=X[1]+X[2];
    printf("%d,%d,",X[1],a);
	X[1]=4;
    printf("%d\n",X[1]);
	return 0;
}

输出 1,3,4

去掉重载运算符的&,编译器提示:表达式必须是可修改的左值

3. C++的cin,cout的实现方式?

网上有很多人讨论cin、cout在C++中属于什么成分。它不像函数,用法却神似函数。这里我们自己实现了myout,可以明显地看出,myout是一个“对象”。 就像上面的变量X一样。

class node
{
    public:
    const node& operator << (int value) const //这么多const和这里的&是什么意思?
    {
        printf("%d",value);
        return *this;
    }
	const node& operator << (double value) const
    {
        printf("%lf",value);
        return *this;
    }
}myout;

通过重载运算符,我们能更方便地输出各种数据类型,而不用写%d,%lf等等标识符。例如:myout<<1<<1.5;

我们可以尝试模拟一下这里的过程。

首先,执行myout<<1。不重载的话,<<是位运算的意思,即myout*2。不过我们既然重载了运算符,就按我们写的方式来。

myout<<1 ,输出了1,并返回了对象myout本身。剩下什么?剩下了myout<<1.5

形象地讲,(myout<<1)<<1.5 == myout << 1.5;

于是,我们又可以调用一遍重载运算符,继续输出1.5!

那么问题来了:如果我不返回一个“引用”,即const node operator << (int value) const{...}好像也能实现啊?

问题在于:如果没有引用,每次返回时,程序都会重新为一个新的对象开辟空间。不管是时间还是空间上,都是一种损耗。

当类里面封装的内容比较庞大时,比如高精度,这样子做显然是不合适的。

4. 两个const是什么成分?

我们知道const int a=0; 此时我们就不能对a进行赋值。

此处的const 作用相同。为了防止我们对myout中的任何参数进行改变,我们加上了const。

后面的const则是防止大括号内的*this被改变。

这就称为“Read Only”.


Author: Tsum
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Tsum !
  TOC