c++学习笔记(7)友元 运算符重载

目录

友元

1 全局函数做友元

2 类做友元

3 成员函数做友元

运算符重载

1.加号运算符重载

(1)成员函数重载+号

(2)全局函数重载+号

2.左移运算符重载

3.递增运算符重载

4.赋值运算符重载

5.关系运算符重载

6.函数调用运算符重载


友元

让一个函数或者类访问另一个类中私有成员

关键字:friend

三种实现:

1 全局函数做友元

使用全局函数访问类中的私有成员

friend void goodGay(Building* building);

#include <iostream>
using namespace std;
#include<string>
class Building
{
	//goodGay全局函数是Building的友元函数,可以访问私有成员
	friend void goodGay(Building* building);
public:
	Building()
	{
		m_SittingRoom = "客厅";
		m_BedRoom = "卧室";
	}
public:
	string m_SittingRoom; // 客厅
private:
	string m_BedRoom;  // 卧室
};
//全局函数
void goodGay(Building * building)
{
	cout << "好朋友全局函数正在访问:" << building->m_SittingRoom << endl;
	cout << "好朋友全局函数正在访问:" << building->m_BedRoom << endl;
}

void test01() {
	Building building;
	goodGay(&building);
}
int main() {
	test01();
	system("pause");
	return 0;
}

2 类做友元

friend class GoodGay;

代码中包括类中构造函数以及成员函数的类外实现(加::作用域)

#include <iostream>
using namespace std;
#include<string>
// 类做友元
class Building; //提前声明
class GoodGay {
public:
	GoodGay();
	void visit();//参观函数 访问building中属性
	Building* building;
};
class Building
{
	//友元类,可以访问私有成员
	friend class GoodGay;
public:
	Building();  //构造函数,本次放在类外实现
public:
	string m_SittingRoom; // 客厅
private:
	string m_BedRoom;  // 卧室
};
Building::Building()
{
	m_SittingRoom = "客厅";

	m_BedRoom="卧室";  
}
GoodGay::GoodGay() {
	//创建建筑物对象
	building = new Building;  //在堆区创建一个对象,用building维护
}
void GoodGay::visit() {
	// 类外实现GoodGay类中的函数
	cout << "GoodGay类正在访问:" << building->m_SittingRoom << endl;
	cout << "GoodGay类正在访问:" << building->m_BedRoom << endl;

}
void test01() {
	GoodGay g;
	g.visit();
}
int main() {
	test01();
	system("pause");
	return 0;
}

3 成员函数做友元

在类中加入

friend void GoodGay::visit();

与全局函数做友元的区别是添加作用域

运算符重载

概念:对已有的运算符进行重新定义,赋予其另一种功能,以适应不同的数据类型

1.加号运算符重载

实现两个自定义数据类型相加的运算

(1)成员函数重载+号

成员函数重载本质调用:

Person p3=p1.operator+(p2);

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


int main() {
	test01();
	system("pause");
	return 0;
}

(2)全局函数重载+号

全局函数重载本质调用:

Person p3=operator+(p1,p2);

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


int main() {
	test01();
	system("pause");
	return 0;
}

运算符重载也可以发生函数重载

对于内置的数据类型的表达式的运算符是不可更改的

不要滥用运算符重载

2.左移运算符重载

作用:输出自定义数据类型

不会利用成员函数重载<<运算符,因为无法实现在左侧

只能利用全局函数重载<<

ostream & operator<<(ostream &cout,Person p){}

#include<iostream>
using namespace std;
#include<string>
//左移运算符重载
class Person {
public:
	
	int m_A;
	int m_B;
};
ostream & operator<<(ostream &cout,Person p) {
	//本质 operator<<(cout,p)  简化 cout<<p
	cout << "m_A=" << p.m_A << "m_B=" << p.m_B <<endl;
	return cout;  //为了实现链式编程,cout后追加多个输出
}
void test01(){
	Person p;
	p.m_A = 10;
	p.m_B = 10;
	cout << p<<endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

3.递增运算符重载

作用:实现自己的整型数据

重载前置++运算符
    返回引用  是为了一直对一个数据进行操作

重载后置++运算符
    传入的int代表占位参数,可以用于区分前置后置递增
    此处要返回值,不能返回引用,因为返回的是局部对象
 

#include<iostream>
using namespace std;
#include<string>
//重载递增运算符
//自定义整型
class MyInt
{
	friend ostream& operator<<(ostream& cout, MyInt myint);
public:
	MyInt() {
		m_num = 0;
	}
	//重载前置++运算符
	//返回引用是为了一直对一个数据进行操作
	MyInt& operator++() {
		m_num++;
		return *this;
	}

	//重载后置++运算符
	//传入的int代表占位参数,可以用于区分前置后置递增
	//此处要返回值,不能返回引用,因为返回的是局部对象
	MyInt operator++(int) {
		//先 记录结果
		MyInt temp = *this;
		//后 递增
		m_num++;

		//最后返回记录的结果

		return temp;
	}
private:
	int m_num;
};
//重载左移运算符
ostream& operator<<(ostream& cout, MyInt myint) {
	cout << myint.m_num;
	return cout;
}
void test01() {
	MyInt myint;
	cout << ++myint << endl;
}
void test02() {
	MyInt myint;
	cout << myint++ << endl;
	cout << myint << endl;
}
int main() {
	//test01();
	test02();
	system("pause");
	return 0;
}

4.赋值运算符重载

c++编译器至少给类添加4个函数

1)默认构造函数(无参,函数体为空)

2)默认析构函数(无参,函数体为空)

3)默认拷贝函数,对属性进行值拷贝

4)赋值运算符operator=对属性进行值拷贝

#include<iostream>
using namespace std;
#include <string>
class Person {
public:
	Person(int age) {
		m_Age = new int(age);
	}
	~Person() {
		//析构函数,释放空间
		if (m_Age != NULL) {
			delete m_Age;  //释放所指区域
			m_Age = NULL;  //指针置空
		}
	}
	//运算符重载
	Person& operator=(Person &p) {
		//返回类型要用&,否则返回的是拷贝构造函数拷贝的值,而不是它本身
		//应该先判断是否有属性在堆区,如果有,先进行释放
		if (m_Age != NULL) {
			delete m_Age;
			m_Age = NULL;

		}
		//进行深拷贝
		m_Age = new int(*p.m_Age);
		//返回自身
		return *this;
	}
	int* m_Age;
};
void test01() {
	Person p1(18);
	Person p2(20);
	Person p3(30);
	//p2=p1;  //默认等号是浅拷贝,会出现重复释放空间,所以重载,编程深拷贝
	p3=p2 = p1;
	cout << "p1年龄" << *p1.m_Age << endl;
	cout << "p2年龄" << *p2.m_Age << endl;
	cout << "p3年龄" << *p3.m_Age << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

5.关系运算符重载

==   != > <

返回bool

#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_Age == p.m_Age && this->m_Name == p.m_Name)
			return true;
		else {
			return false;
		}
	}
	bool operator!=(Person& p) {
		if (this->m_Age != p.m_Age && this->m_Name != p.m_Name)
			return false;
		else {
			return true;
		}
	}
	string m_Name;
	int m_Age;
};
void test01() {
	Person p1("tom", 18);
	Person p2("amy", 18);
	if (p1 == p2) {
		cout << "p1和p2相等" << endl;
	}
	else {
		cout << "p1和p2不相等" << endl;
	}
	if (p1 != p2) {
		cout << "p1和p2不相等" << endl;
	}
	else {
		cout << "p1和p2相等" << endl;
	}

}
int main() {
	test01();
	system("pause");
	return 0;
}

6.函数调用运算符重载

()小括号重载

由于重载后使用的方式非常像函数的调用,因此被称为仿函数

仿函数没有固定的写法,非常灵活

myprint("hello world");  // ()重载实现,使用非常像函数,所以又称仿函数
MyPrint02("hello world!!!"); //函数实现

匿名函数对象  类()
cout << MyAdd()(200, 300) << endl;

#include<iostream>
using namespace std;
#include <string>
class MyPrint {
public:
	void operator()(string test) {
		cout << test << endl;
	}
};
void MyPrint02(string test) {
	cout << test << endl;
}
void test01() {
	MyPrint myprint;
	myprint("hello world");  // ()重载实现,使用非常像函数,所以又称仿函数
	MyPrint02("hello world!!!"); //函数实现
}
//仿函数非常灵活,无固定写法,如:
class MyAdd {
public:
	int operator()(int a,int b) {
		return a + b;
	}
};
void test02() {
	MyAdd myadd;
	int result = myadd(100, 200);
	cout << result << endl;

	//匿名函数对象  类()
	cout << MyAdd()(200, 300) << endl;
}
int main() {
	test01();
	test02();
	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值