运算符重载
运算符重载
1.友元
如果将其他类、函数设置为类的友元,那么友元、函数就可以在前一个类的类定义之外访问其私有成员了,用friend关键字声明友元
友元的三种形式:普通函数,成员函数,友元类
2.友元—普通函数形式
1 | class Point{ |
3.友元—成员函数形式
1 | class Point; |
4.友元类
1 | class Line{ |
友元的声明要注意和函数的形式一一对应上
友元的特点
- 友元不受类中访问权限的限制——可访问私有成员
- 友元破坏了类的封装性
- 不能滥用友元 ,友元的使用受到限制
- 友元是单向的——A类是B类的友元类,则A类成员函数中可以访问B类私有成员;但并不代表B类是A类的友元类,如果A类中没有声明B类为友元类,此时B类的成员函数中并不能访问A类私有成员
- 友元不具备传递性——A是B的友元类,B是C的友元类,无法推断出A是C的友元类
- 友元不能被继承——因为友元破坏了类的封装性,为了降低影响,设计层面上友元不能被继承
运算符重载
运算符重载是希望自定义类类型在操作时与内置类型保持一致
不能重载的运算符包括:
. 成员访问运算符 .*成员指针访问运算符 ?:三目运算符 ::作用域限定符 sizeof长度运算符
运算符重载的规则与形式
- 运算符重载有以下规则
运算符重载时 ,其操作数类型必须要有自定义类类型或枚举类型 ——不能全都是内置类型
其优先级和结合性还是固定不变的 a == b + c
操作符的操作数个数是保持不变的
运算符重载时 ,不能设置默认参数 ——如果设置了默认值,其实也就是改变了操作数的个数
逻辑与 && 逻辑或 || 就不再具备短路求值特性 ,进入函数体之前必须完成所有函数参数的计算, 不推荐重载
不能臆造一个并不存在的运算符 @ $ 、
- 运算符重载的形式
运算符重载的形式有三种:
- 采用友元函数的重载形式
- 采用普通函数的重载形式
- 采用成员函数的重载形式
以加法运算符为例,认识这三种形式。
加法运算符重载
1.友元函数的重载形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 //复数
class Complex{
public:
Complex(int real, int image)
:_real(real)
,_image(image)
{}
void print() const{
couot << _real << "+" << _image << "i" << endl;
}
//声明友元
frind Complex operator+(const Complex &lhs, const Complex &rhs);
private:
int _real;
int _image;
};
//对+进行重载,采用友元函数的重载形式
//一般定义一个普通函数operator+运算符,写明计算逻辑
Complex operator+(const Complex &lhs, const Complex &rhs){
return Complex(lhs._real + rhs._real,lhs_image + rhs._image);
}
void test(){
Complex cx1(1,2);
Complex cx2(3,4);
//Complex cx = operator+(cx1,cx2);
//本质
Complex cx3 = cx1 + cx2;
cx3.print();
}
2.采用成员函数的重载形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 //复数
class Complex{
public:
Complex(int real, int image)
:_real(real)
,_image(image)
{}
void print() const{
couot << _real << "+" << _image << "i" << endl;
}
//声明友元
Complex operator+(const Complex &rhs){
return Complex(_real + rhs._real,_image + rhs._image);
}
private:
int _real;
int _image;
};
void test0(){
Complex cx1(1,2);
Complex cx2(3,4);
//Complex cx3 = cx1.operator+(cx2);
//本质
Complex cx3 = cx1 + cx2;
cx3.print();
}
重载形式的选择
- 不会修改操作数的值的运算符,倾向于采用友元函数的方式重载
- 会修改操作数的值的运算符,倾向于采用成员函数的方式重载
- 赋值=、下标[ ]、调用()、成员访问->、成员指针访问-> 运算符必须是成员函数形式重载*
- 与给定类型密切相关的运算符,如递增、递减和解引用运算符,通常应该是成员函数形式重载
- 具有对称性的运算符可能转换任意一端的运算对象,例如相等性、位运算符等,通常应该是友元形式重载
对++运算符重载
1 | //复数 |
本文是原创文章,采用CC BY-NC-SA 4.0协议,完整转载请注明来自The Yue