1.友元
类: 实现对数据的隐藏和封装,类中的数据成员一般定义为私有类型,这样的情况下类内通过成员函数才能够读取。
友元: 是一种允许非成员函数或者非当前类的成员函数访问一个类的私有成员的一种机制,破坏封装的特性。
友元的实现方式:
- 友元函数
- 友元类
- 友元成员函数
1.1 友元函数
友元函数不属于任何一个类,是类外的一个函数,但是可以访问类内的私有成员。
友元函数需要类内"声明",类外定义。
例:客厅 卧室
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Room
{
private:
string bed_room="$$$$$$$$$$";
public:
string living_room="*****";
// 声明友元函数
friend void fun(Room & r);
};
void fun(Room & r)
{
cout << r.living_room << endl;
cout << r.bed_room << endl;
}
int main()
{
Room r1;
cout << r1.living_room << endl;
fun(r1);
return 0;
}
友元函数使用需要注意:
- 友元函数内部没有this指针
- 友元函数的声明可以放置在类的任何位置,不受权限修饰符的影响
- 一个友元函数理论上可以访问多个类,分类在每一个类中进行声明
1.2 友元类
当一个类B成为了另一个类Test的"好朋友"时,类test中的所有成员都可以被类B访问,此时类B就是类Test的友元类。
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int a;
public:
Test(int a):a(a){}
void fun()
{
cout << a << endl;
}
// 声明友元类
friend class B;
};
class B
{
public :
void test_print(Test & t)
{
cout << t.a << endl;
}
void test_a(Test & t)
{
cout << t.a << endl;
}
};
int main()
{
Test t1(10);
t1.fun (); // 10
B b1;
b1.test_print (t1); // 10
b1.test_a (t1); // 10
return 0;
}
友元类使用的时候需要注意:
- 友元关系不能继承
- 友元关系不具有交换性
- 友元关系不具有传递性
1.3 友元成员函数
使类B中的成员函数称为类Test的友元成员函数,这样类B的该成员函数就是类Test的友元成员函数,也就可以访问类Test的所有成员
步骤:
- 在Test类中声明友元成员函数
- 成员函数在类外进行定义
- 在类B中声明此成员函数
- 在类B之前声明类Test
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
// 4.在类B之前声明类Test
class Test;
class B
{
public:
// 3.在类B中声明此成员函数
void test_friend(Test & t);
};
class Test
{
private:
int a;
public:
Test(int a):a(a){}
void fun()
{
cout << a << endl;
}
// 1.在Test类中声明友元成员函数
friend void B::test_friend(Test & t);
};
// 2.成员函数在类外进行定义
void B::test_friend(Test & t)
{
cout << t.a << endl;
}
int main()
{
Test t1(100);
B b1;
b1.test_friend (t1); // 100
return 0;
}
2.运算符重载
c++中可以把部分的运算符看成是函数,此时运算符也就是可以重载。本质是函数重载
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int a;
public:
Test(int a):a(a){}
int get_a()
{
return a;
}
};
int main()
{
Test t1(1);
Test t2(1);
Test t3= t1+t2; // 报错
// int a1=1;
// int b1=1;
// int c=a1+b1;
cout << t3.get_a () << endl;// 2
return 0;
}
重载的方式:
- 友元函数运算符重载
- 成员函数运算符重载

2.1 友元函数运算符重载
双目运算为例:+
运算符函数名:operator 符号

cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int a;
public:
Test(int a):a(a){}
int get_a()
{
return a;
}
friend Test operator +(const Test & t1,const Test & t2);
};
Test operator +(const Test & t1,const Test & t2)
{
// Test t3;
// t3.a = t1.a+t2.a;
// return t1.a+t2.a;
return Test(t1.a+t2.a);}
int main()
{
Test t1(1);
Test t2(1);
// Test t4=t2;
Test t3= t1 + t2;
cout << t3.get_a () << endl;// 2
return 0;
}

单目运算符:++为例
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int a;
public:
Test(int a):a(a){}
int get_a()
{
return a;
}
friend Test operator +(const Test & t1,const Test & t2);
friend Test operator ++(Test & t1); // 前置
friend Test operator ++(Test & t1,int); // 后置
};
Test operator +(const Test & t1,const Test & t2)
{
// Test t3;
// t3.a = t1.a+t2.a;
// return t1.a+t2.a;
return Test(t1.a+t2.a);
}
Test operator ++(Test & t1)
{
return ++t1.a;
}
Test operator ++(Test & t1,int)
{
return t1.a++;
}
int main()
{
Test t1(10);
Test t2(1);
// Test t4=t2;
Test t3= t1 + t2;
cout << t3.get_a () << endl;// 11
cout << (++t1).get_a () << endl; // 11
cout << (t1++).get_a () << endl; // 11
return 0;
}
2.2 成员函数运算符重载
成员函数中有this指针,所以成员函数运算符重载可以比友元函数运算符重载少一个参数。因为this指针默认接收第一个参数。(this指针默认指向第一个参数)
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int a;
public:
Test(int a):a(a){}
int get_a()
{
return a;
}
// friend Test operator +(const Test & t1,const Test & t2);
// friend Test operator ++(Test & t1); // 前置
// friend Test operator ++(Test & t1,int); // 后置
Test operator +(const Test & t2);
Test operator ++(); // 前置
Test operator ++(int); // 后置
};
Test Test::operator +(const Test & t2)
{
return Test(this->a+t2.a);
}
Test Test::operator ++()
{
return ++this->a;
}
Test Test::operator ++(int)
{
return this->a++;
}
int main()
{
Test t1(10);
Test t2(1);
// Test t4=t2;
Test t3= t1 + t2;
cout << t3.get_a () << endl;// 11
cout << (++t1).get_a () << endl; // 11
cout << (t1++).get_a () << endl; // 11
cout << (t1++).get_a () << endl; // 12
return 0;
}

2.3 特殊运算符重载
部分运算符不支持友元函数运算符重载,只支持成员函数运算符重载。
2.3.1 赋值运算符重载
如果程序员不写,那么编译器会自动添加

cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int a;
public:
Test(int a):a(a){}
int get_a()
{
return a;
}
// 编译器添加的运算符重载
Test & operator =(const Test & t)
{
cout << "运算符" << endl;
this->a=t.a;
return *this;
}
};
int main()
{
Test t1(10);
Test t2(1);
t2=t1; // 调用赋值运算符重载
Test t3(t1);// 拷贝构造函数
Test t4=t2; // 拷贝构造函数
return 0;
}
2.3.2 类型转换运算符重载
必须使用成员函数运算符,且格式比较特殊。
函数名:operator 要转化成的类型
不需要写返回值的类型
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
class Test
{
private:
int a;
public:
Test(int a):a(a){}
int get_a()
{
return a;
}
// 编译器添加的运算符重载
Test & operator =(const Test & t)
{
cout << "运算符" << endl;
this->a=t.a;
return *this;
}
operator int()
{
return this->a;
}
operator string()
{
string s="hello";
return s;
}
};
int main()
{
Test t1(10);
Test t2(1);
t2=t1; // 调用赋值运算符重载
int a=t1;
string b=t1;
cout << a << endl;// 10
cout << b << endl;// string
return 0;
}
注意:
- 重载的运算符一定在c++语言中已经存在的运算符,不能创建新的运算符
- 所以运算符重载不支持函数的默认值
- 重载时不能改变运算符的优先级以及结合性以及语义
- 运算符重载必须包含自定义的数据类型
- 一般情况下,双目运算符建议使用友元函数运算符重载,单目运算符建议使用成员函数运算符重载
3.std:: string字符串类
字符串对象是一种特殊类型的容器,专门设计用于操作字符序列
cpp
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
int main()
{
string s; // 调用无参构造
// 判断是否为空
cout << s.empty () << endl; // 1 bool:true:1 false:0
string s1="hello";// 调用有参构造
string s2("abc");// 调用有参构造
cout << (s1==s2) << endl; // 0
string s3(s2); // 调用拷贝有参构造 s3=s2
// 保留几个字符
// 参数1:char * 字符串
// 参数2:整型数值
string s4("ABCD",3);
cout << s4 << endl; // ABC
// 不保留前几个字符
// 参数1:string 对象
// 参数2:整型数值
string s5(s1,3);
cout << s5 << endl; // lo
// 保存几个字符
// 参数1:整型数值
// 参数2:char字符
string s6(5,'A');
cout << s6 << endl; // AAAAA
// 交换
swap(s5,s6);
cout << s5 << endl;// AAAAA
cout << s6 << endl;// lo
// 拼接
string s7=s5+s6;
cout << s7 << endl;// AAAAAlo
// 最后追加字符串
s7.append ("hhhhh");
cout << s7 << endl;// AAAAAlohhhhh
// 最后追加字符
s7.push_back ('B');
cout << s7 << endl;// AAAAAlohhhhhB
// 插入
// 参数1:插入位置
// 参数2:插入的内容
s7.insert (1,"22");
cout << s7 << endl;// A22AAAAlohhhhhB
// 删除
// 参数1:从第几个元素开始删除
// 参数2:删除的字符数量
s7.erase (4,10);
cout << s7 << endl;// A22AB
// 替换
// 参数1:起始位置(下标)
// 参数2:替换的字符个数
// 参数3:替换的内容
s7.replace (1,2,"*");
cout << s7 << endl;// A*AB
// 清空
s7.clear ();
cout << "-----:" << s7 << endl;// -----:
// string ---> char *
char c[20];
strcpy(c,s5.c_str ()); // 在尾部会添加\0
cout << c << endl; // AAAAA
char c1[20];
// string --> char *
// 参数1:保存的数组
// 参数2:字符个数
// 参数3:位置
s5.copy(c1,6,0);
cout << c1 << endl;// AAAAA
return 0;
}