四、运算符重载
1. 友元
1.1 概念(掌握)
类实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,仅能通过类的成员函数才能读写。如果数据成员定义为公共的,则又破坏了封装性。但是某些情况下,需要频繁读写类的数据成员,特别是在对某些成员函数多次调用时,由于参数传递、类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。
友元是一种定义在类外部的普通函数,但他需要在类内进行说明,为了和该类的成员函数加以区别,在说明时前面加以关键字friend
学习友元最终的目的是把友元运用在运算符重载上,其它情况下不要使用友元,因为会破坏面向对象的特性。
友元主要分为以下几种使用情况:
1.2 友元函数(重点)
友元函数是一种类外的函数,但是需要在类内结合friend关键字进行说明(非声明),需要注意以下几点:
1.3 友元类(熟悉)
当一个类B成为了另一个类A的“朋友”时,类A的所有成员就可以被类B访问,此时类B是类A的友元类。
需要注意的是:
1.4 友元成员函数(熟悉)
可以使类B中的某一个成员函数成为类A的友元成员函数,这样类B中只有这个成员函数可以访问类A的所有成员。
2. 运算符重载(重点)
2.1 概念
函数可以重载,运算符也是一种特殊的函数,因此运算符也可以重载。
函数的组成部分:
上述的每个组成部分运算符都拥有。
C++中的运算符默认的操作类型只支持基本数据类型,例如+支持整型浮点型等类型的运算,但是对于很多用户自定义的类型(Dog类、Cat类、Test类等)的对象也需要支持运算符,例如 狗+狗。此时可以在代码中重载运算符,赋予这些运算符处理新的类型的功能。
可以被重载的运算符:
算术运算符:+、-、*、/、%、++、--
位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]
不被重载的运算符:
成员运算符 .、指针运算符 *、三目运算符 ? :、sizeof、作用域 ::
2.2 友元函数运算符重载
可以使用友元函数进行运算符重载。
2.3 成员函数运算符重载
也可以使用成员函数进行运算符重载,成员函数的运算符函数对应的输入参数比同样使用友元函数实现的友元函数的参数少一个。
2.4 其它运算符重载
2.4.1 赋值运算符重载
如果写一个空类,按照目前所学内容,编译器会自动添加:
除了上述三者外,编译器还会增加若干内容,其中包括赋值运算符重载函数。
赋值运算符重载函数只支持成员函数运算符重载,不支持友元函数运算符重载的方式。
通常无需手动编写赋值运算符重载,以下情况需要手动编写,编译器不在自动添加赋值运算符重载函数:
2.4.2 类型转换运算符重载
可以使自定义类型的对象自动转换为任意类型,此函数也只能使用成员函数运算符重载。
2.5 注意事项
3. 字符串类 std::string(熟悉)
再学习此类,主要涉及此类的一些构造函数和成员函数。
std::string是一种特殊容器的类型,用于操作字符序列。
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
string s; // 创建一个内容为空的字符串对象
// 是否为空
cout << s.empty() << endl; // 1
// 隐式调用构造函数
string s1 = "Abc";
// 相当于
string s2("Abc");
cout << (s1 == s2) << endl; // 1
// 拷贝构造函数
string s3 = s2;
string s4(s3);
cout << s3 << " " << s4 << endl; // Abc Abc
// 参数1:源字符串 char*
// 参数2:从前往后保留的字符数
string s5("ABCDEFG",3);
cout << s5 << endl; // ABC
// 参数1:源字符串 string
// 参数2:从前往后不保留的字符数
s = "ABCDEFG";
string s6(s,3);
cout << s6 << endl; // DEFG
// 参数1:字符数量
// 参数2:字符 char
string s7(5,'A');
cout << s7 << endl; // AAAAA
// 交换
swap(s6,s7);
cout << s6 << " " << s7 << endl; // AAAAA DEFG
s1 = "ABCD";
// 向后追加字符串,支持链式调用
s1.append("EF").append("GHI").append("ZZZ"); // ABCDEFGHIZZZ
cout << s1 << endl;
// 字符串连接
s1 = s6+s7;
cout << s1 << endl; // AAAAADEFG
// 向后追加一个字符
s1.push_back('*');
cout << s1 << endl; // AAAAADEFG*
// 参数1:插入的位置
// 参数2:插入的内容
s1.insert(1,"###");
cout << s1 << endl; // A###AAAADEFG*
// 参数1:替换的起始位置
// 参数2:替换的字符数量
// 参数3:替换的新内容
s1.replace(0,7,"!!!!");
cout << s1 << endl; // !!!!ADEFG*
// 参数1:删除的起始位置
// 参数2:删除的字符数
s1.erase(4,3);
cout << s1 << endl; // !!!!FG*
// 清空
s1.clear();
cout << s1.length() << endl; // 0
// C字符串→C++字符串
char c[20] = "hello";
s = c;
cout << s << endl; // hello
// C++字符串→C字符串
s = "Good afternoon!";
// c = s; 错误
s.copy(c,s.size()); // 全拷贝
cout << c << endl; // Good afternoon!
// 参数1:源字符串
// 参数2:拷贝的数量
// 参数3:拷贝的起始位置
s.copy(c,9,5);
cout << c << endl; // afternoonrnoon!
// 还可以使用下面的函数完成
char d[20];
strcpy(d,s.c_str()); // c_str()返回一个临时的const char*
cout << d << endl; // Good afternoon!
return 0;
}