曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 3796|回复: 1
打印 上一主题 下一主题

使用成员函数重载运算符

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
跳转到指定楼层
楼主
发表于 2011-8-17 23:59:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在 C++ 中,函数可以重载,运算符也可以重载,重载运算符的好处就是可以将新的数据类型整合到程序设计环境中。运算符重载的通用形式如下:
[C++] 纯文本查看 复制代码
type classname::operator#(arg-list)
{
   //相对于该类的运算
}

上面通过使用 operator函数 来重载运算符。其中 '#' 符号代表要重载的运算符,type 表示具体运算返回值的类型,它可以是任意类型,但通常返回值的类型与重载运算符所在的类应该是同一类型。

运算符函数可以是类的成员函数也可以不是,非类成员运算符函数一般为类的友员函数。

下面的示例程序使用成员函数重载运算符。
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;

class three_d {
    int x, y, z;    //三维坐标的三个坐标值
public:
    three_d() { x = y = z = 0; }
    three_d(int i, int j, int k) { x = i; y = j; z = k; }
    
    three_d operator+(three_d op2);    //op1被隐式指定
    three_d operator=(three_d op2); //op1被隐式指定

    void show();
};

//重载 '+' 运算符
three_d three_d::operator+(three_d op2)
{
    three_d temp;

    temp.x = x + op2.x;    //做加法运算,此处的 + 号为普通的运算符号
    temp.y = y + op2.y;
    temp.z = z + op2.z;

    return temp;
}

//重载赋值运算符 '='
three_d three_d::operator=(three_d op2)
{
    x = op2.x;    //这里的 '=' 符号保持原始含义,为普通赋值运算符
    y = op2.y;
    z = op2.z;

    return *this;
}

//输出 x, y, z 的坐标值
void three_d::show()
{
    cout << x << ", ";
    cout << y << ", ";
    cout << z << "\n";
}

int main()
{
    three_d a(1, 2, 3), b(10, 10, 10), c;

    a.show();
    b.show();

    c = a + b;    //将对象 a 和 b 相加
    c.show();

    c = a + b + c;    //将对象 a, b, c 相加
    c.show();

    c = b = a;    //多重赋值运算
    c.show();
    b.show();

    return 0;
}

运行输出:
$ ./rloperator
1, 2, 3
10, 10, 10
11, 12, 13
22, 24, 26
1, 2, 3
1, 2, 3
由程序可以看出,重载运算符是一种大范围上的一种提示,比如 c = a + b; 表示将两个对象 a 和 b 相加,然后赋值给 c 对象,但是本质上还是让 a 和 b 这两个对象中的成员变量做普通的加法运算,最后的运算结果赋给 c 对象中的成员。

如上面程序所示,我们重载了 '+' 号运算符,这是一个二元运算符,但 operator+(three_d op2) 中只有 op2 这个参数,看上去有点违背常理,但实际情况并非如此,其理由是:当使用成员函数来重载二元运算符,只需要将一个参数显示地传递给它,而另一个参数则隐式地使用 this 指针来传递。因此,在下面的代码中:
[Plain Text] 纯文本查看 复制代码
temp.x = x + op2.x

x 指的是 this-x ,即运算符函数是通过一个对象调用的,而 x 就是这个对象的变量。在所有的情况下,运算符左边的对象将调用运算符函数,而右边的对象则被作为参数传递给函数。如在 a + b 中,a  作为调用运算符函数的对象,而 b 则将作为参数传递给函数。

在上面的程序中,需要注意的是,如 a + b 这样通过运算符函数来做的加法运算,并不会改变 a 或者 b 中的内容。道理很简单,如 3 + 4 这种普通的加法运算里,得到的只是结果 7,但不会改变 3 或者 4 的值。然而,实际上并没有原则规定,在重载运算符的运算中不能改变操作数的值,但是一般建议重载运算符的行为最好和它的原始含义保持一致。

同样的,operator+() 返回的是一个 three_d 类型的对象,但实际上函数的返回值可以是任意的 C++ 类型。但是如果它返回的不是 three_d 对象,那么 c = a + b 这样的表达式则不能进行下去,所以如此设法并没有什么意义。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
沙发
 楼主| 发表于 2011-8-18 09:51:00 | 只看该作者

成员函数重载一元运算符

也可以重载一元运算符,比如 ++ ,-- 或者别的。

当使用成员函数来重载一元运算符时,并没有对象被显式地传递给运算符。事实上,this 指针被作为参数隐式地传递给运算符函数,而运算将作用于调用这个函数的对象。如下面程序所示:
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;

class three_d {
    int x, y, z;    //三维坐标的三个坐标值
public:
    three_d() { x = y = z = 0; }
    three_d(int i, int j, int k) { x = i; y = j; z = k; }
    
    three_d operator+(three_d op2);    //op1被隐式指定
    three_d operator=(three_d op2); //op1被隐式指定
    three_d operator++();    //前缀++

    void show();
};

//重载 '+' 运算符
three_d three_d::operator+(three_d op2)
{
    three_d temp;

    temp.x = x + op2.x;    //做加法运算,此处的 + 号为普通的运算符号
    temp.y = y + op2.y;
    temp.z = z + op2.z;

    return temp;
}

//重载赋值运算符 '='
three_d three_d::operator=(three_d op2)
{
    x = op2.x;    //这里的 '=' 符号保持原始含义,为普通赋值运算符
    y = op2.y;
    z = op2.z;

    return *this;
}

//重载前缀++,函数里没有参数
three_d three_d::operator++()
{
    x++;    //对 3 个坐标值进行增量运算
    y++;
    z++;
    return *this;
}


//输出 x, y, z 的坐标值
void three_d::show()
{
    cout << x << ", ";
    cout << y << ", ";
    cout << z << "\\n";
}

int main()
{
    three_d a(1, 2, 3), b(10, 10, 10), c;

    a.show();
    b.show();

    c = a + b;    //将对象 a 和 b 相加
    c.show();

    c = a + b + c;    //将对象 a, b, c 相加
    c.show();

    c = b = a;    //多重赋值运算
    c.show();
    b.show();

    ++c;        //对 c 做增量运算
    c.show();

    return 0;
}

运行输出:
$ ./rloperator2
1, 2, 3
10, 10, 10
11, 12, 13
22, 24, 26
1, 2, 3
1, 2, 3
2, 3, 4
上面重载的是 '++' 运算符的前缀形式,也可以重载它的后缀形式。重载 '++' 的后缀形式如下所示:
[Plain Text] 纯文本查看 复制代码
three_d three_d::operator++(int notused);

notused 参数没有被函数使用,将被忽略。这个参数只是让编译器识别增量运算符是前缀形式还是后缀形式。下面代码还添加了类 three_d 中运算符 ++ 的后缀形式重载函数:
[C++] 纯文本查看 复制代码
#include <iostream>
using namespace std;

class three_d {
    int x, y, z;    //三维坐标的三个坐标值
public:
    three_d() { x = y = z = 0; }
    three_d(int i, int j, int k) { x = i; y = j; z = k; }
    
    three_d operator+(three_d op2);    //op1被隐式指定
    three_d operator=(three_d op2); //op1被隐式指定
    three_d operator++();    //前缀++
    three_d operator++(int notused);    //++的后缀形式

    void show();
};

//重载 '+' 运算符
three_d three_d::operator+(three_d op2)
{
    three_d temp;

    temp.x = x + op2.x;    //做加法运算,此处的 + 号为普通的运算符号
    temp.y = y + op2.y;
    temp.z = z + op2.z;

    return temp;
}

//重载赋值运算符 '='
three_d three_d::operator=(three_d op2)
{
    x = op2.x;    //这里的 '=' 符号保持原始含义,为普通赋值运算符
    y = op2.y;
    z = op2.z;

    return *this;
}

//重载前缀++,函数里没有参数
three_d three_d::operator++()
{
    x++;    //对 3 个坐标值进行增量运算
    y++;
    z++;
    return *this;
}

three_d three_d::operator++(int notused)
{
    three_d temp = *this;
    x++;
    y++;
    z++;

    return temp;    //返回原始值
}

//输出 x, y, z 的坐标值
void three_d::show()
{
    cout << x << ", ";
    cout << y << ", ";
    cout << z << "\\n";
}

int main()
{
    three_d a(1, 2, 3), b(10, 10, 10), c;

    a.show();
    b.show();

    c = a + b;    //将对象 a 和 b 相加
    c.show();

    c = a + b + c;    //将对象 a, b, c 相加
    c.show();

    c = b = a;    //多重赋值运算
    c.show();
    b.show();

    ++c;        //对 c 做增量运算
    c.show();

    c++;        //后缀增量运算
    c.show();

    a = ++c;    //a 得到 c 增加之后的值,因此 a 和 c 是相等的
    a.show();
    c.show();

    a = c++;    //a 得到 c 增量之前的值,因此 a 和 c 是不相等的
    a.show();
    c.show();


    return 0;
}

运行输出:
$ ./rloperator3
1, 2, 3
10, 10, 10
11, 12, 13
22, 24, 26
1, 2, 3
1, 2, 3
2, 3, 4
3, 4, 5
4, 5, 6
4, 5, 6
4, 5, 6
5, 6, 7
上面程序中,如果运算符 ++ 在对象之前,那么函数 operator++() 将被调用;反之,那么函数 operator++(int notused) 将被调用。同样的规则适用于类的减量运算符。

不能重载的运算符有:
. :: .* ?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-21 12:43 , Processed in 0.064018 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表