IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++面向对象OOP-友元与运算符重载 -> 正文阅读

[C++知识库]C++面向对象OOP-友元与运算符重载

为什么要把友元和运算符重载放在一起讲? 因为运算符重载主要是针对类,所以会涉及到很多被保护和私有的成员数据获取。如果不借助友元,实现会很复杂。而使用了友元技术能够直接访问到被保护或者私有的成员数据让运算符重载操作变得更简单。

1 友元

1.1 友元可以干什么?

友元可以访问类内被保护或者私有的成员和方法。

1.2友元的分类

1.2.1 友元函数

1、友元函数声明的时候在不受类权限影响,即在public、private、protected权限下效果相同
2、友元函数在类中声明需要加上friend


Cow.h

#pragma once
#include<string>

using namespace std;

class Cow {
public:
	Cow();
	~Cow();

	// 声明外部函数是该类的友元函数
	friend int getCowWeigth(const Cow& other);

private:
	int weigth;
	string sex;
};

Cow.cpp

#include "Cow.h"

Cow::Cow() {
	this->weigth = 12;
	string sex = "母牛";
}

Cow::~Cow() {

}

main.cpp

#include<iostream>
#include"Cow.h"

// 友元函数
int getCowWeigth(const Cow& other) {
	// other.weigth = 14;  // 如果形参不加限制那么这里修改类成员数据也是可以的
	return other.weigth;  // 跳过类权限直接拿到数据
}

int main() {
	Cow cow1;
	
	cout << getCowWeigth(cow1) << endl;

	return 0;
}

结果:

12

1.2.2 类成员函数作为友元

类成员函数作为友元该成员函数可以访问类中的私有属性
Cow.h

#pragma once
#include<string>
#include "Search.h"  // 这里必须要包含头文件,仅仅靠声明会报错

using namespace std;

class Cow {
public:
	Cow();
	~Cow();

	// 类成员函数作为友元
	friend int Search::s1(const Cow& other);

private:
	int weigth;
	string sex;
};

Cow.cpp

#include "Cow.h"

Cow::Cow() {
	this->weigth = 12;
	string sex = "母牛";
}

Cow::~Cow() {

}

Search.h

#pragma once

class Cow;  // 注意此处,声明类

class Search {

public:
	Search();
	~Search();
	
	int s1(const Cow& other);

private:

};



Search.cpp

#include "Search.h"
#include "Cow.h"  // 注意此处

Search::Search() {

}

Search::~Search() {

}

// 类成员函数作为友元
int Search::s1(const Cow& other) {
	return other.weigth;
}

main.cpp

#include<iostream>
#include "Cow.h"
#include "Search.h"

int main() {

	Cow cow1;
	Search s1;

	cout << s1.s1(cow1) << endl;

	return 0;
}

结果:

12

1.2.3 友元类

友元类:友元类中所有成员函数都可以访问这个类的私有属性


Cow.h

#pragma once
#include<string>

using namespace std;

class Cow {
public:
	Cow();
	~Cow();

	// 友元类
	friend class Search;

private:
	int weigth;
	string sex;
};

Cow.cpp

#include "Cow.h"

Cow::Cow() {
	this->weigth = 12;
	string sex = "母牛";
}

Cow::~Cow() {

}

Search.h

#pragma once

class Cow;  // 注意此处,声明类

class Search {

public:
	Search();
	~Search();
	
	int s1(const Cow& other);  // 不能修改值
	void s2(Cow& other);  // 可以修改值

private:

};

Search.cpp

#include "Search.h"
#include "Cow.h"  // 注意此处

Search::Search() {

}

Search::~Search() {

}


int Search::s1(const Cow& other) {
	return other.weigth;
}

void Search::s2(Cow& other) {
	other.weigth = 13;
}

main.cpp

#include<iostream>
#include "Cow.h"
#include "Search.h"

int main() {

	Cow cow1;
	Search s1;

	cout << s1.s1(cow1) << endl;
	s1.s2(cow1);
	cout << s1.s1(cow1) << endl;

	return 0;
}

结果:

12
13

2 运算符重载

2.1 运算符重载中友元函数与友元类的区别

1、使用友元类只有一个参数,还有一个参数是对象本身省略,更符合封装要求。
但是无法实现普通类型+类这种,只能实现类+普通类型
2、使用友元全局函数更直观(参数两个),方便实现a+b,b+a这种。但是不利于封装。

2.2 运算符重载注意事项

在这里插入图片描述

在这里插入图片描述

2.3 重载+、-算数运算符

实现一头猪+一头羊=猪肉多少斤
如果同时用了友元函数和类成员函数做友元要注意调用冲突问题,一般用一种方法实现即可。
这里我使用两种方法演示,,后面为了偷懒我会使用某一种。

2.3.1 类成员函数做友元

原理:类1.operator运算符(类2/其他);

Pig.h

#pragma once
#include<string>
using namespace std;

class Sheep;  // 没必要导入头文件

class Pig {
public:
	Pig(int weight);
	~Pig();

	string operator+(const Sheep& other);

private:
	int weight;
};

Pig.cpp

#include<sstream>
#include "Pig.h"
#include "Sheep.h"

Pig::Pig(int weight) {
	this->weight = weight;
}

Pig::~Pig() {

}

string Pig::operator+(const Sheep& other) {
	stringstream ret;

	ret << "猪+羊=" << other.weight * 5 + this->weight << "斤猪肉";

	return ret.str();
}


Sheep.h

#pragma once
#include"Pig.h"

class Sheep {
public:
	Sheep(int weight);
	~Sheep();

	// 友元函数只能实现pig+sheep,无法实现sheep+pig
	friend string Pig::operator+(const Sheep& other);

private:
	int weight;
};

Sheep.cpp

#include "Sheep.h"


Sheep::Sheep(int weight) {
	this->weight = weight;
}

Sheep::~Sheep() {

}

main.cpp

#include<iostream>
#include "Pig.h"
#include "Sheep.h"

int main() {
	Pig pig1(50);
	Sheep sheep1(60);

	cout << pig1 + sheep1 << endl;

	return 0;
}

结果:

猪+羊=350斤猪肉

2.3.2 友元函数


Pig.h

#pragma once
#include<string>
using namespace std;

class Sheep;

class Pig {
public:
	Pig(int weight);
	~Pig();

	friend string operator+(const Pig& pig, const Sheep& sheep);
	friend string operator+(const Sheep& sheep, const Pig& pig);

private:
	int weight;
};



Pig.cpp

#include<sstream>
#include "Pig.h"

Pig::Pig(int weight) {
	this->weight = weight;
}

Pig::~Pig() {

}

Sheep.h

#pragma once
#include<string>
using namespace std;

class Pig;

class Sheep {
public:
	Sheep(int weight);
	~Sheep();

	friend string operator+(const Pig& pig, const Sheep& sheep);
	friend string operator+(const Sheep& sheep, const Pig& pig);

private:
	int weight;
};



Sheep.cpp

#include "Sheep.h"


Sheep::Sheep(int weight) {
	this->weight = weight;
}

Sheep::~Sheep() {

}

main.cpp

#include<iostream>
#include<string>
#include<sstream>
#include "Pig.h"
#include "Sheep.h"

using namespace std;

// 实现a+b
string operator+(const Pig& pig, const Sheep& sheep) {
	stringstream ret;

	ret << "猪+羊=" << sheep.weight * 5 + pig.weight << "斤猪肉";

	return ret.str();

}

// 实现b+a
string operator+(const Sheep& sheep, const Pig& pig) {
	stringstream ret;

	ret << "猪+羊=" << sheep.weight * 5 + pig.weight << "斤猪肉";

	return ret.str();

}

int main() {
	Pig pig1(50);
	Sheep sheep1(60);

	cout << pig1 + sheep1 << endl;
	cout << sheep1 + pig1<< endl;

	return 0;
}

结果:

猪+羊=350斤猪肉
猪+羊=350斤猪肉

2.4 重载=赋值运算符

利用已经创建的对象来修改已经创建的对象,就是我们常说的赋值构造函数


Sheep.h

#pragma once
#include<string>
using namespace std;

class Pig;

class Sheep {
public:
	Sheep(int weight);
	~Sheep();
	string Descrition()const;  // 不修改私有数据设成const,这样const对象也可以访问该方法

	// 重载=运算符
	Sheep& operator=(const Sheep& other);

private:
	int weight;
};

Sheep.cpp

#include<sstream>
#include "Sheep.h"


Sheep::Sheep(int weight) {
	this->weight = weight;
}

Sheep::~Sheep() {

}

string Sheep::Descrition()const {
	stringstream ret;
	ret << "weigtf:" << this->weight;

	return ret.str();
}

Sheep& Sheep::operator=(const Sheep& other) {
	// 当成员数据出现指针要注意深浅拷贝问题
	if (this == &other) {
		return *this;  // 防止出现f1 = f1;
	}
	this->weight = other.weight;

	return *this;  // 链式编程f1 = f2 = f3;
}

main.cpp

#include<iostream>
#include "Sheep.h"

using namespace std;


int main() {
	Sheep s1(12);
	cout << s1.Descrition() << endl;

	Sheep s2(13);
	cout << s2.Descrition() << endl;

	// 利用已有对象改变现有对象
	s1 = s2;
	cout << s1.Descrition() << endl;
	cout << s2.Descrition() << endl;

	return 0;
}

结果:

weigtf:12
weigtf:13
weigtf:13
weigtf:13

2.5 重载<、>、==逻辑运算符


Sheep.h

#pragma once
#include<string>
using namespace std;

class Sheep {
public:
	Sheep(int weight);
	~Sheep();
	string Descrition()const;  // 不修改私有数据设成const,这样const对象也可以访问该方法

	// 重载<运算符
	bool operator<(const Sheep& other);

private:
	int weight;
};

Sheep.cpp

#include<sstream>
#include "Sheep.h"


Sheep::Sheep(int weight) {
	this->weight = weight;
}

Sheep::~Sheep() {

}

string Sheep::Descrition()const {
	stringstream ret;
	ret << "weigtf:" << this->weight;

	return ret.str();
}

bool Sheep::operator<(const Sheep& other) {
	if (this->weight < other.weight) {
		return true;
	}
	else {
		return false;
	}
}

main.cpp

#include<iostream>
#include "Sheep.h"

using namespace std;


int main() {
	Sheep s1(12);
	cout << s1.Descrition() << endl;

	Sheep s2(13);
	cout << s2.Descrition() << endl;

	cout << (s1 < s2) << endl;

	return 0;
}

结果:

weigtf:12
weigtf:13
1


2.6 重载[]下标运算符


Sheep.h

#pragma once
#include<string>
using namespace std;

// 枚举并把类型重命名
typedef enum NUM {
	one,
	two,
	tree
}Num_type;  

class Sheep {
public:
	Sheep(int weight);
	~Sheep();
	string Descrition()const;  // 不修改私有数据设成const,这样const对象也可以访问该方法

	// 重载<运算符
	int operator[](Num_type numtype);

private:
	int weight;

};

Sheep.cpp

#include<sstream>
#include "Sheep.h"


Sheep::Sheep(int weight) {
	this->weight = weight;
}

Sheep::~Sheep() {

}

string Sheep::Descrition()const {
	stringstream ret;
	ret << "weigtf:" << this->weight;

	return ret.str();
}

// 重载[],这样方便阅读,具体案例中one、two这种可以换成具体的单词
int Sheep::operator[](Num_type numtype) {
	switch (numtype) {

	case one:
		return 1;

	case two:
		return 2;

	case tree:
		return 3;
	default:
		return 0;
	}
}

main.cpp

#include<iostream>
#include "Sheep.h"

using namespace std;


int main() {
	Sheep s1(12);
	cout << s1[two] << endl;
	cout << s1[one] << endl;

	return 0;
}

结果:

2
1

2.7 重载<<、>>输入输出运算符

可以输入或者输出对象特地内容。
最好使用友元函数,因为友元类和我们正常使用相反不好理解。


Sheep.h

#pragma once
#include<string>
using namespace std;

class Sheep {
public:
	Sheep(int weight);
	~Sheep();

	// 友元函数
	friend ostream& operator<<(ostream& cout, const Sheep& shepp);

private:
	int weight;

};

Sheep.cpp

#include<sstream>
#include "Sheep.h"


Sheep::Sheep(int weight) {
	this->weight = weight;
}

Sheep::~Sheep() {

}

main.cpp

#include<iostream>
#include "Sheep.h"

using namespace std;

ostream& operator<<(ostream& cout, const Sheep& sheep) {
	cout << sheep.weight;

	return cout; // 要返回这个cout否则无法链式编程
}


int main() {
	Sheep s1(12);
	cout << s1 << endl;

	return 0;
}

结果:

12


2.8 重载类型运算符

2.8.1 普通类型->类类类型

如果在创建对象的时候使用普通类型赋值,实际上会调用类的自定义带参构造函数
原理: A a = 12; 实际会调用A(int)带参构造函数。


Sheep.h

#pragma once
class Sheep {
public:
	Sheep(int weigth);
	~Sheep();
	int Describtion()const;

private:
	int weigth;
};
____```

Sheep.cpp

```cpp
#include "Sheep.h"

Sheep::Sheep(int weigth) {
	this->weigth = weigth;
}

Sheep::~Sheep() {
	
}

int Sheep::Describtion()const {
	return weigth;
}

main.cpp

#include<iostream>
#include"Sheep.h"

using namespace std;

int main() {
	// 普通类型到类类型
	Sheep s1 = 13;  // 调用带参构造函数

	cout << s1.Describtion() << endl;
	return 0;
}

结果:

13


2.8.2 类类型A->类类型B

实现:
B b;
A a = b;

利用拷贝构造函数
A(const B& other);


Bigsheep.h

#pragma once

class Sheep;

class BigSheep {
public:
	BigSheep(int weigth);
	BigSheep(const Sheep& other);
	~BigSheep();
	int Describtion()const;


private:
	int weigth;
};

Bigsheep.cpp

#include "BigSheep.h"
#include "Sheep.h"

BigSheep::BigSheep(int weigth) {
	this->weigth = weigth;
}

BigSheep::~BigSheep() {

}

BigSheep::BigSheep(const Sheep& other) {
	this->weigth = other.weigth;
}

int BigSheep::Describtion()const {
	return weigth;
}

Sheep.h

#pragma once
class Sheep {
public:
	Sheep(int weigth);
	~Sheep();
	int Describtion()const;

	friend class BigSheep;

private:
	int weigth;
};

Sheep.cpp

#include "Sheep.h"

Sheep::Sheep(int weigth) {
	this->weigth = weigth;
}

Sheep::~Sheep() {
	
}

int Sheep::Describtion()const {
	return weigth;
}

main.cpp

#include<iostream>
#include"Sheep.h"
#include "BigSheep.h"

using namespace std;

int main() {
	
	Sheep s1 = 13;
	BigSheep Bigsheep = s1;

	cout << Bigsheep.Describtion() << endl;

	return 0;
}

结果:

13


2.8.3 类类型->普通类型

类型运算符重载不要返回类型,添加会出错
operator int();


Sheep.h

#pragma once
class Sheep {
public:
	Sheep(int weigth);
	~Sheep();
	int Describtion()const;

	// 重载类型运算符,不能加返回值
	operator int() const;

private:
	int weigth;
};

Sheep.cpp

#include "Sheep.h"

Sheep::Sheep(int weigth) {
	this->weigth = weigth;
}

Sheep::~Sheep() {
	
}

int Sheep::Describtion()const {
	return weigth;
}

Sheep::operator int() const {
	return weigth;
}

main.cpp

#include<iostream>
#include"Sheep.h"

using namespace std;

int main() {
	
	Sheep s1 = 13;

	int num = s1;  // 类类型到普通类型

	cout << num << endl;

	return 0;
}

结果:

13


后续完善

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:06:35  更:2022-11-05 00:11:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 5:21:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码