浅谈运算符重载与友元函数

Vector强化版

大纲:
1. 运算符重载
3. 友元函数
4. 思考一个问题

先把Vector类的代码放出来
相比上次的Vector省略了一些

// Vector.h
#ifndef VECTOR_H
#define VECTOR_H
class Vector
{
private:
    int x;
    int y;
public:
    void show() const;
};

#endif
// Vector.cpp
#include "Vector.h"
#include 

void Vector::show() const
{
    using namespace std;
    cout << x << "," << y << endl;
    return ;
}

。。。。。。

如果要把一个矢量相加减
你是否梦想着可以用下面的代码来实现呢?

//test.cpp
#include "Vector.h"
#include 
using namespace std;
int main()
{
    Vector v1(2,3);
    Vector v2(3,4);
    Vector vp;
    Vector vm,vm2;
    vp = v1 + v2;
    vm = v1 * v2;
    vm2 = 3 * vm;
    cout << v;
    return 0;
}

可是,Vector类对象并不是普通的内置类型
计算机并不知道如何将他们相加相乘
更不知道如何用cout将这个类输出
这个时候,全都需要我们自己定义运算符

运算符重载

两个double类型的数据可以用运算符+相加
两个int类型的数据也可以用运算符+相加
诶,+号就像函数一样
可以根据不同的参数类型执行不同的操作
其实,运算符重载和函数重载是一样的呢
再其实,运算符其实就是个函数
下面先放出一个运算符重载的实例

// 函数原型
Vector operator+(Vector v1,Vector v2);
// 函数定义
Vector operator+(Vector v1,Vector v2)
{
    Vector temp;
    temp.x = v1.x + v2.x;
    temp.y = v1.y + v2.y;
    return temp;
}

在这个函数定义中,
+号在函数里用了operator+表示
注意:这里说明了,运算符是可以有两种表示方式的
一种是运算符表示法: v = v1 + v2;
y一种是函数表示法:v = operator+(v1,v2);
然后其他的东东和普通的函数时一样的
可是,这个函数是不能用的

还记得以前说到的,
非成员函数,是不能够访问类的私有成员的
要解决这个问题
1. 在类中定义运算符重载
2. 友元函数

类中运算符重载与普通运算符重载区别

还记得以前说到的
类成员函数,会隐式的传递this指针
下面还是先给一个类中定义运算符重载的例子

Vector Vector::operator+(Vector v1)
{
    Vector temp;
    temp.x = v1.x + x;
    temp.y = v1.y + y;
    return temp;
}

区别:
1. 使用作用域解析运算符
2. 少传递了一个参数,原本需要两个操作数的+
只传递了一个对象?

在类中,会隐式的传递自身作为运算符的一个操作数
如:v = v1 + v2
用函数表示法可表示为
v = v1.operator+(v2);

友元函数

对上面的问题,还有一种解决方案
虽然非成员函数无法访问类的私有成员
但我可以通过一种特殊的方式
让非成员函数获得访问私有成员的特权
友元函数!!

友元函数的语法要求有两个:
1. 函数的原型前面加上friend关键字
2. 函数原型必须放在类定义内部

下面给例子

// 函数原型
class Vector
{
    ...
public:
    ...
    friend Vector operator+(Vector v1,Vector v2);
}

// 函数定义
Vector operator+(Vector v1,Vector v2)
{
    Vector temp;
    temp.x = v1.x + v2.x;
    temp.y = v1.y + v2.y;
    return temp;
}

函数的调用方式略有不同
v = v1 + v2;
实际上是这样的函数调用
v = operator+(v1, v2);

其他操作的实现

乘法和加法类似
也有友元版运算符重载
和类内运算符重载两种形式
不过有一个需要思考的
vm2 = 3 * v2
这个该怎么办呢?

在类内运算符重载中
二元运算符的第一个操作数是调用对象本身
第二个操作数是函数参数
如:v = v1 + v2
用函数表示法可表示为
v = v1.operator+(v2);

vm2 = 3 * v2
只有通过定义一个友元函数才能够解决
因为 3 不是一个对象,
无法调用对象内的运算符函数来计算
只能够通过友元函数来实现

// 函数原型
class Vector
{
    ...
public:
    ...
    friend Vector operator*(int d ,Vector v);
}

// 函数定义
Vector operator*(int d ,Vector v)
{
    Vector temp;
    temp.x = v.x * d;
    temp.y = v.y * d;
    return temp;
}

思考

  1. 上面的运算符重载能否实现以下操作
    v = v1 + v2 + v3 + v4;

  2. 运算符重载,是否能够重载任意运算符?

  3. 重载能否改变现有的运算规则
    (比如把两个int类的+法自定义)

  4. 如何实现<< 的运算符重载从而实现
    cout << v;

1.

可以
假设这里用的是类内的运算符重载
根据+号从左往右结合
先算v1 + v2
v = v1.operator(v2) + v3 + v4;
然后根据函数定义
该函数返回一个Vector对象
也就是说
v1.operator(v2)本身就是一个Vector 对象
然后这个对象与v3结合,再使用+号
v = v1.operator(v2).operator+(v3) + v4;
后面以此类推
关键是在该运算符函数返回对象(当然也可以返回对象的引用)

2.

还是有很多限制的
比如:
1. 运算符操作数至少一个数是用户自定义的类型
2. 不违反现有的句法规则
3. 不创造新的运算符
4. 一部分运算符不可以重载
一部分运算符只能在类内作为类成员函数重载
一部分运算符类内类外均可

具体的可以自行了解
当然加减乘除都是类内类外均可的

3

哎呀……上面不小心回答完了

4

先放例子

// 函数原型
class Vector
{
    ...
public:
    ...
    friend ostream & operator<<(ostream & os, const Vector & temp );
}

// 函数定义
ostream & operator<<(ostream & os, const Vector & temp )
{
    os << temp.x << "," << temp.y << endl ;
    return os;
}

详细解释看 c++ primer plus p392 - 394吧
不大好解释呢
反正……cin是一个ostream类的对象
所以要想
cin << v;
函数的形参列表就必须与上面对应
(见函数定义)

一些比较好的博客
http://blog.csdn.net/dingyuanpu/article/details/5852825
http://blog.csdn.net/zgl_dm/article/details/1767201

你可能感兴趣的:(7班推送)