友元和运算符重载
# 1 友元
# 1.1 友元函数
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,格式为:friend 类型 函数名(形式参数); 一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
//友元函数的目的就是为了访问类的私有数据成员
//全局函数作友元函数
friend double Distance(Point &a, Point &b);
//类的成员函数作友元函数
friend double ManagerPoint::Distance(Point &a, Point &b);
# 1.2 友元类
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。 当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。
定义友元类的语句格式如下:
friend class 类名;
其中:friend和class是关键字,类名必须是程序中的⼀个已定义过的类。
例如,以下语句说明类B是类A的友元类:
class A
{
...
public:
friend class B;
...
};
经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。
# 1.3 注意事项
- 因为友元不是授权类的成员,所以它不受其所在类的声明区域public private和protected的影响。通常我们选择把所有友元声明组织在一起并放在类头之后。
- 友元关系不能被继承。
- 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
- 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的声明。
# 2 运算符重载
运算符重载的本质是函数重载。
# 2.1 重载规则
可被重载的运算符:new, new[], delete, delete[], +, -, , /, %, ^, &, |, ~, !, =, ..., ,, ->, ->, (), []
不能重载的运算符:.; ::; .*; ?: ;
重载方式: 友元重载和成员重载
# 2.2 单目操作符重载
重点区分前置操作还是后置操作
// 前++
friend Complex& operator++(Complex& c);
Complex& operator++(Complex& c)
{
c._x++;
c._y++;
return c;
}
// 后++
friend const Complex operator++(Complex &c,int);
const Complex operator++(Complex &c,int)
{
Complex t(c._x,c._y);
c._x++;
c._y++;
return t;
}
// 也可以用下面的方式定义
const Complex operator++(int)
{
Complex t = *this;
_x++;
_y++;
return t;
}
# 2.3 输入输出运算符重载(只能通过友元函数重载)
需要通过友元来实现,避免修改c++的标准库。
friend ostream& operator<<(ostream &os, const Complex& c);
friend istream& operator>>(istream &is, Complex& c);
ostream& operator<<(ostream &os, const Complex& c)
{
os<<"("<<c._x<<","<<c._y<<")";
return os;
}
istream& operator>>(istream&is, Complex& c)
{
is>>c._x>>c._y;
return is;
}
# 2.4 只能通过成员函数重载的运算符
# 2.4.1 赋值运算符重载 (operator=)
用一个己有对象,给另外一个己有对象赋值。两个对象均己创建结束后,发 生的赋值行为。
String& String::operator=(const String& str)
{
//1.首先判断是否赋值给自己
if (this == &str)
return *this;
//2.删除指针之前分配的内存
delete[] m_data;
//3.拷贝,需要分配内存,最好通过new进行分配
m_data = new char[strlen(str.m_data) + 1 ];
strcpy(m_data, str.m_data);
return *this;
}
# 2.4.2 数组下标运算符 (operator[])
设 x 是类 X 的一个对象,则表达式 x[y] 可被解释为 x.operator[](y)
int& operator[](int index)
{
return v[i];
}
# 2.4.3 函数调用符号 (operator())
把类对象像函数名一样使用。
仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。
#include <iostream>
using namespace std;
class Sqr
{
public:
int operator()(int i)
{
return i*i;
}
double operator()(double d)
{
return d*d;
}
};
int main()
{
Sqr sqr;
int i = sqr(4);
double d = sqr(5.5);
cout<<i<<endl;
cout<<d<<endl;
return 0;
}