4.4 友元
4.4.1 全局函数做友元
但是我们作为好朋友,想要它可以访问私有成员属性呢?
示例代码:
#include<iostream>
using namespace std;
#include<string>
//成员函数做友元
class Building
{
friend void goodfriend(Building* building); //googfriend全局函数是Building的友元,可以访问Building中的私有成员
public:
Building() //初始化
{
m_SittingRoom = "客厅";
m_Bedroom = "卧室";
}
public:
string m_SittingRoom;//客厅
private:
string m_Bedroom;//卧室
};
//全局函数
void goodfriend(Building* building) //函数形参
{
cout << "好朋友全局函数 正在访问:" << building->m_SittingRoom << endl;
cout << "好朋友全局函数 正在访问:" << building->m_Bedroom << endl; //私有成员变量不能访问
}
void test01()
{
Building building; //实例化对象
goodfriend(&building);
}
int main() {
test01();
system("pause");
return 0;
}
4.4.2 类做友元
#include<iostream>
#include<string>
using namespace std;
//类做友元
class Building; //goodFriend类中使用了Building类,但是当前还没有定义。给编译器说我后面会写
class goodFriend
{
public:
goodFriend();
//构造函数声明,如果不进行声明,goodFriend 类中的构造函数试图使用默认构造函数来初始化 building 成员指针
void visit(); //参观函数 访问Building中的属性
Building* building; //使用Building类维护一个building的指针
};
class Building
{
public:
Building(); //构造函数
string m_SittingRoom;//客厅
private:
string m_Bedroom;//卧室
};
//类外写成员函数
Building::Building() //Building类下的Building函数
{
m_SittingRoom = "客厅";
m_Bedroom = "卧室";
}
goodFriend::goodFriend()
{
//创建建筑物对象
building = new Building;
}
void goodFriend::visit() //goodFrinend下的构造函数
{
cout << "好基友正在访问:" << building->m_SittingRoom << endl;
}
void test01()
{
goodFriend ss;
ss.visit();
}
int main() {
test01();
system("pause");
return 0;
}
当我们访问私有成员时。
如何解决?
4.4.3 成员函数做友元
示例代码:
#include<iostream>
using namespace std;
#include<string>
class Building; // 前置声明 Building 类
class goodGay
{
public:
goodGay();
void visit(); //visit可以访问Building的私有成员
void visit2(); //visit不可以访问Building的私有成员
Building * building;
};
class Building
{
friend void goodGay::visit(); //goodGay下的visit成员函数作为本类的友元
public:
Building();
string m_sittingRoom;
private:
string m_bedRoom;
};
//类外写成员函数
Building::Building()
{
m_sittingRoom = "客厅";
m_bedRoom = "卧室";
}
goodGay::goodGay()
{
building = new Building; //创建对象Building,并使用指针维护这个对象
}
void goodGay::visit()
{
cout << "visit正在访问:" << building->m_sittingRoom << endl;
cout << "visit正在访问:" << building->m_bedRoom << endl;
}
void goodGay::visit2()
{
cout << "visit正在访问:" << building->m_sittingRoom << endl;
/*cout << "visit正在访问:" << building->m_bedRoom << endl;*/
}
void test01()
{
goodGay ss;
ss.visit();
ss.visit2();
}
int main() {
test01();
system("pause");
return 0;
}
4.5运算重载符
4.5.1 加法运算符重载
要实现这种计算结果创建出一个新的对象 。一种方法可以通过定义成员函数。
通过成员函数实现:
通过全局函数实现
示例代码如下:
#include<iostream>
using namespace std;
#include<string>
//加号运算符重载
class Person
{
public:
//1、成员函数重载+号
/*Person operator+(Person &p)
{
Person temp;
temp.m_a = this->m_a + p.m_a;
temp.m_b = this->m_b + p.m_b;
return temp;
}*/
int m_a;
int m_b;
};
//2、全局函数重载+号
Person operator+(Person& p1, Person& p2)
{
Person temp;
temp.m_a = p1.m_a + p2.m_a;
temp.m_b = p2.m_b + p2.m_b;
return temp;
}
void test01()
{
Person p1;
p1.m_a = 10;
p1.m_b = 10;
Person p2;
p2.m_a = 10;
p2.m_b = 10;
Person p3 = p1 + p2;
cout << "p3的m_a为:" << p3.m_a << endl;
cout << "p3的m_b为:" << p3.m_b << endl;
}
int main() {
test01();
system("pause");
return 0;
}
运算符重载也可以发生函数重载
运行结果如下:
示例代码如下:
#include<iostream>
using namespace std;
#include<string>
//加号运算符重载
class Person
{
public:
1、成员函数重载+号
//Person operator+(Person &p)
//{
// Person temp;
// temp.m_a = this->m_a + p.m_a;
// temp.m_b = this->m_b + p.m_b;
// return temp;
//}
int m_a;
int m_b;
};
//2、全局函数重载+号
Person operator+(Person& p1, Person& p2)
{
Person temp;
temp.m_a = p1.m_a + p2.m_a;
temp.m_b = p1.m_b + p2.m_b;
return temp;
}
//函数重载版本
Person operator+(Person& p1, int num)
{
Person temp;
temp.m_a = p1.m_a + num;
temp.m_b = p1.m_b + num;
return temp;
}
void test01()
{
Person p1;
p1.m_a = 10;
p1.m_b = 10;
Person p2;
p2.m_a = 10;
p2.m_b = 10;
//成员函数重载本质调用
//Person p3 = p1.operator+(p2); //本质是将p2传到成员函数中 p1.operator+(p2)= p1 + p2
//全局函数重载本质调用
Person p3 = operator+(p1, p2); 本质是将p1,p2传到全局函数operator+中
/*Person p3 = p1 + p2;*/
//运算符重载也可以发生函数重载
Person p4 = p1 + 100;
cout << "p3的m_a为:" << p3.m_a << endl;
cout << "p3的m_b为:" << p3.m_b << endl;
cout << "p4的m_a为:" << p4.m_a << endl;
cout << "p4的m_b为:" << p4.m_b << endl;
}
int main() {
test01();
system("pause");
return 0;
}
4.5.2 左移运算符重载
左移运算符:<<。cout经常使用的。
成员p成功打印。但是当加上endl换行时代码报错。
这是因为全局函数operator<<的返回类型是void,链式思想不能使用。因此要对返回值类型进行修改。
代码正常。
#include<iostream>
using namespace std;
#include<string>
//左移运算符重载
class Person
{
public:
int m_a;
int m_b;
};
//只能利用全局函数重载左移运算符
ostream & operator<<(ostream & out, Person &p)//全局只能有一个cout,不能创建出一个新的因此需要使用引用传递
{
out << "m_a:" << p.m_a<< "m_b:" << p.m_b;
return out;
}
void test01()
{
Person p;
p.m_a = 10;
p.m_b = 10;
cout << p << endl;
}
int main() {
test01();
system("pause");
return 0;
}
4.5.3 递增运算符重载
返回引用格式打印正确了。因为引用是起别名,操作的是同一段数据。
示例代码如下:
#include<iostream>
using namespace std;
#include<string>
//递增运算符重载 ++
class MyInteger
{
friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
MyInteger()
{
m_Num = 0;
}
//重载++运算符前置 返回引用是为了对一个数据进行操作
MyInteger &operator++()
{
//先进行++
m_Num++;
//再将自身进行一个返回
return *this;
}
//重载++运算符后置
private:
int m_Num;
};
ostream& operator<<(ostream& cout, MyInteger myint)
{
cout << myint.m_Num;
return cout;
}
void test01()
{
MyInteger myint;
cout << ++(++myint) << endl;
cout << myint << endl;
}
int main() {
test01();
system("pause");
return 0;
}
后置递增运算符
示例代码如下:
#include<iostream>
using namespace std;
#include<string>
//递增运算符重载 ++
class MyInteger
{
friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
MyInteger()
{
m_Num = 0;
}
//重载++运算符前置 返回引用是为了对一个数据进行操作
MyInteger &operator++()
{
//先进行++
m_Num++;
//再将自身进行一个返回
return *this;
}
//重载++运算符后置 int代表一个占位参数,用于区分前置和后置递增
MyInteger operator++(int)
{
//先记录当时结果
MyInteger temp = *this;
//后递增
m_Num++;
//最后将记录结果返回
return temp;
}
private:
int m_Num;
};
ostream& operator<<(ostream& cout, MyInteger myint)
{
cout << myint.m_Num;
return cout;
}
void test01()
{
MyInteger myint;
cout << ++(++myint) << endl;
cout << myint << endl;
}
void test02()
{
MyInteger myint;
cout << myint++ << endl;
cout << myint << endl;
}
int main() {
/*test01();*/
test02();
system("pause");
return 0;
}
4.5.4 赋值运算符
在没有调用析构函数时,成功打印。加入析构函数(堆区空间需要手动释放),结果如下
#include<iostream>
using namespace std;
#include<string>
//赋值运算符重载
class Person
{
public:
Person(int age) //函数创建了一个年龄比如18
{
m_Age=new int (age); //将18开辟到堆区,并让指针来维护数据(管理内存)
}
~Person()
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
}
int* m_Age;
};
void test01()
{
Person p1(18);
Person p2(20);
p2 = p1;
cout << *p1.m_Age << endl;
cout << *p2.m_Age << endl;
}
int main() {
test01();
system("pause");
return 0;
}
此时代码崩溃了。
原因:
解决方案:深拷贝
添加重载运算符函数。进行深拷贝。
代码没有报错了。 但是依然存在问题。
那咱们目前写的函数可以进行连等于吗?
为什么会这样?因为在执行p2=p1时候,返回值是void。用p3等于void明显不对。
此时成功打印。
4.5.5 关系运算符重载
如果直接判断自定义类型?
代码报错。
加入重载函数代码运行正常。
!=类似,示例代码如下。
#include<iostream>
using namespace std;
#include<string>
//关系运算符重载
class Person
{
public:
Person(string name, int age)
{
m_Name = name;
m_Age = age;
}
//重载==
bool operator==(Person& p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
return false;
}
//重载!=
bool operator!=(Person& p)
{
if (this->m_Name != p.m_Name || this->m_Age != p.m_Age)
{
return true;
}
return false;
}
string m_Name;
int m_Age;
};
void test01()
{
Person p1("张三",18);
Person p2("张三",18);
Person p3("李四",19);
if (p1 == p2)
{
cout << "p1等于p2" << endl;
}
else
{
cout << "p1不等于p2" << endl;
}
if (p1 != p3)
{
cout << "p1不等于p3" << endl;
}
else
{
cout << "p1等于p3" << endl;
}
}
int main() {
test01();
system("pause");
return 0;
}
4.5.6 函数调用运算符重载
test02(),实现了相加。
仿函数使用起来非常灵活。
示例代码:
#include<iostream>
using namespace std;
#include<string>
//函数调用运算符重载
//打印输出类
class MyPrint
{
public:
//重载函数调用运算符
void operator()(string test)
{
cout << test << endl;
}
};
//加法类
class MyAdd
{
public:
int operator()(int num1, int num2)
{
return num1 + num2;
}
};
void test02()
{
MyAdd myadd;
int ref=myadd(100, 20);
cout << ref << endl;
//匿名函数对象 MyAdd()是创建匿名对象,运行完就会释放 类名+小括号就是匿名对象
cout << MyAdd()(100, 100) << endl;
}
void MyPrint02(string test)
{
cout << "hello world" << endl;
}
void test01()
{
MyPrint myprint;
myprint("hello world"); //由于使用非常类似于函数调用,因此称为仿函数
MyPrint02("hello world");
}
int main() {
test01();
test02();
system("pause");
return 0;
}