(2)类和对象——友元、运算符重载

友元

程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元技术

友元目的

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

友元关键字

friend

友元三种实现:

  • 全局函数做友元
  • 类做友元
  • 成员函数做友元

全局函数做友元

class Building {
	//声明goodGay全局函数是Building好朋友,可以访问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;
}

类做友元

class Building;
class GoodGay {
public:
	GoodGay();
	void visit();//参观函数 访问Building中的属性
	Building* building;
};
class Building {
	friend class GoodGay;//GoodGay类是本类的好朋友,可以访问本类中的私有内容
public:
	Building();
	string m_SittingRoom;
private:
	string m_BedRoom;
};
Building::Building() {//类外写成员函数
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}
GoodGay::GoodGay() {
	building = new Building;//创建建筑物对象
}
void GoodGay::visit() {
	cout << "好基友 访问:" << building->m_SittingRoom << endl;
	cout << "好基友 访问:" << building->m_BedRoom << endl;
}
void test01() {
	GoodGay gg;
	gg.visit();
}
int main() {
	test01();
	system("pause");
	return 0;
}

成员函数做友元

class Building;
class GoodGay {
public:
	GoodGay();
	void visit();//让visit函数可以访问Building中私有成员
	void visit2();//让visit2函数不可以访问Building中私有成员
	Building* building;
};
class Building {
	friend void GoodGay::visit();//告诉编译器,GoodGay类下的visit成员函数可以访问Building类的私有内容
public:
	Building();
	string m_SittingRoom;
private:
	string m_BedRoom;
};
Building::Building() {
	m_SittingRoom = "客厅";
	m_BedRoom = "卧室";
}
GoodGay::GoodGay() {
	building = new Building;
}
void GoodGay::visit() {
	cout << "visit 函数正在访问:" << building->m_SittingRoom << endl;
	cout << "visit 函数正在访问:" << building->m_BedRoom << endl;
}
void GoodGay::visit2() {
	cout << "visit2 函数正在访问:" << building->m_SittingRoom << endl;
	//cout << "visit 函数正在访问:" << building->m_BedRoom << endl;//报错
}
int main() {
	GoodGay gg;
	gg.visit();
	gg.visit2();
	system("pause");
	return 0;
}

运算符重载

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

加号运算符重载

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

class Person {
public:
	成员函数重载+
	//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;
};
//全局函数重载+
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 + p2;
	//Person p3 = p1.operator+(p2);成员函数重载本质调用
	//Person p3 = operator+(p1, p2);全局函数重载本质调用
	cout << "p3.m_A = " << p3.m_A << endl;//打印 20
	cout << "p3.m_B = " << p3.m_B << endl;//打印 20
	Person p4 = p1 + 100;//运算符重载也可以发生函数重载
	cout << "p4.m_A = " << p4.m_A << endl;//打印 110
	cout << "p4.m_B = " << p4.m_B << endl;//打印 110
}
int main() {
	test01();
	system("pause");
	return 0;
}

总结:

  • 对于内置的数据类型表达式的的运算符是不可能改变的
  • 不要滥用运算符重载

左移运算符重载

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

class Person {
public:
	//成员函数重载左移运算符 p.operator<<(cout) 简化:p << cout
	//不会利用成员函数重载<<运算符,因为无法实现 cout 在左侧
	//void operator<<(cout) {
	//}
	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;
	return cout;
}
void test01() {
	Person p;
	p.m_A = 10;
	p.m_B = 10;
	cout << p << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

递增运算符重载

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

class MyInteger {
	friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
	MyInteger() {
		m_Num = 0;
	}
	//重载前置++
	MyInteger& operator++() {
		m_Num++;//先进行++运算
		return *this;//再将自身返回
	}
	//重载后置++
	MyInteger operator++(int) {//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;// 1
}
void test02() {
	MyInteger myint;
	cout << myint++ << endl;// 0
	cout << myint << endl;// 1
}
int main() {
	test01();
	test02();
	system("pause");
	return 0;
}

总结:前置递增返回引用,后置递增返回值

赋值运算符重载

C++编译器至少给一个类添加4个函数:

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数,对属性进行值拷贝
  • 赋值运算符operator=对属性进行值拷贝

如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题。

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) {
		//编译器提供浅拷贝,m_Age = p.m_Age;
		//应该判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
		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);
	p3 = p2 = p1;
	cout << "p1年龄:" << *p1.m_Age << endl;// 18
	cout << "p2年龄:" << *p2.m_Age << endl;// 18
	cout << "p3年龄:" << *p3.m_Age << endl;// 18
}
int main() {
	test01();
	system("pause");
	return 0;
}

关系运算符重载

作用:可以让两个自定义类型对象进行对比操作

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;
	}
	string m_Name;
	int m_Age;
};
void test01() {
	Person p1("Tom", 18);
	Person p2("Tom", 20);
	if (p1 == p2) {
		cout << "p1 和 p2 相等" << endl;
	}
	else{
		cout << "p1 和 p2 不相等" << endl;
	}
}
int main() {
	test01();
	system("pause");
	return 0;
}

函数调用运算符重载

  • 函数调用运算符()也可以重载
  • 由于重载后使用的方式非常像函数的调用,因此也称仿函数
  • 仿函数没有固定写法,非常灵活
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 num1, int num2) {
		return num1 + num2;
	}
};
void test02() {
	MyAdd myadd;
	int ret = myadd(100, 100);
	cout << "ret = " << ret << endl;// 打印 ret = 200
	cout << MyAdd()(100, 200) << endl;//匿名函数对象
}
int main() {
	test01();
	test02();
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值