主要介绍以下几点:
- 类友元函数的创建方式;
- 运算符重载的限制;
- 如何重载运算符(以 + 为例);
- 运算符重载与友元函数;
- ( << )运算符的重载;
类的友元函数
通常来说,外部实现对类私有成员的访问,只能通过类的公有方法,然而友元提供了另一用方法。
class A
{
private:
...
public:
...
friend void func(...);
//注意,和类的const成员函数不一样,
//友元函数属于正常的函数,不能声明成const型
//friend void func(...) const;
};
//func不是类的成员,定义时不需要A::func()
//func定义时无需加friend前缀
void func(...){
...
}
定义友元函数时需要注意以下两点:
- 无需(类名::函数名)的形式去定义,因为友元不是类的成员;
- 定义时无需加friend前缀;
所以,也不能用成员运算符调用友元函数。
那么问题就来了,都有类的公有方法了,为什么多此一举搞一个友元函数?
在运算符重载那一部分,会详细介绍友元函数的具体用法。
重载运算符的限制
- 重载后的运算符,必须要有一个操作数是用户定义的类型(防止用户为标准类型重载运算符);
- 重载运算符不能违反运算符原有的语法(不能将 + 重载成 - ,将 * 重载成 /);
- 不能创建新的运算符;
- 一些特殊运算符不能重载;
不能重载的运算符如下:
sizeof : 计算空间运算
. : 成员运算
.* : 成员指针运算
:: : 作用域运算
?: : 条件运算
typeid : RTTI运算符
四个强制类型转换运算符
仅能通过成员函数进行重载的运算符(重载的函数必须是类的成员函数)
= : 赋值运算
() : 函数调用运算
[] : 下标运算
-> : 通过指针访问类成员运算
运算符重载
假设我有一个类Vector,类Vector表示xoy平面的向量(Vector仅有两个私有变量x和y)
class Vector{
privatr:
double x;
double y;
public:
//构造函数与析构函数,具体内容就不写了
Vector();
Vector(double xx, double yy);
~Vector();
};
Vector a = {1.0, 2.0}, b = {1.5, 2.5};
上面用Vector创建了两个向量a和b,现在我想做向量的加法,使:
Vector c = a + b;
此时就需要重载“+”运算符。
具体重载方法如下:
class Vector{
...
public:
Vector & operator+(const Vector v) const;
}
Vector & Vector::operator+(const Vector v) const {
Vector c;
c.x = x + v.x;
c.y = y + v.y;
return c;
}
此时需要注意,c = a + b重载运算符“+”,使用的是运算符函数,其实际形式是
// c = a + b与下面的形式等价:
c = a.operator+( b );
所以该函数,隐式的使用a(因为调用了它的方法),显式的使用对象b(被作为参数传递);
同理,乘法运算 c = a * 2.0也可以实现,只需将参数的形式变化一下即可。
那么,如果想要算 c = 2.0 * a 呢? 2.0只是一个double常量,它怎么调用“它的方法”呢?
这里就需要使用上面的友元函数了。
因为友元函数不是类的成员函数,非成员函数不是由对象调用的,它所有的参数都是显式参数,所以, c = 2.0 * a如果调用非成员函数的运算符重载,则编程下面这种形式:
c = operator* (2.0, a);
所以重载“*”运算需要定义两种重载函数:
class Vector{
private:
...
public:
...
Vector & operator*(const Vector v) const;
friend Vector & operator*(double n, const Vector v);
//或者将友元换成下面这种成员函数也可以
Vector & operator*(double n, const Vector v) const {
//此处实际是调用第一个函数
return v * n;
}
}
重载 <<
如果我们用下面这个成员函数重载<<,运行下列指令会发生什么?
void operator<<(std::ostream & os, const Vector &v);
...
Vector a = {1.0, 2.0};
std::cout << a << "a" << a << "a" << std::endl;
很明显,cout << a后返回的是void,再执行 void << "a"会报错。此时,我们需要按照下面这种方式重载<<.
std::ostream & operator<<(std::ostream & os, const Vector &v);
...
Vector a = {1.0, 2.0};
std::cout << a << "a" << a << "a" << std::endl;
这样,cout << a后返回的还是一个cout,再执行 cout << “a” ……