C++核心编程-4、类和对象2—友元与运算重载符

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值