1、友元
为了能访问某个类中的所有成员方法和成员数据
两种方式:
① 友元函数
在类的头文件中增加:friend 函数名(参数);
[例]有一个计算机类,需要对这个计算机的CPU进行升级
头文件:
#pragma once
#include <string>
using namespace std;
class Computer
{
public:
Computer();
string description();
//定义update函数为Computer类的友元函数,可以访问类中的任何数据和方法(在public/private中任意地方都可定义)
friend void update(Computer &computer);
private:
string cpu;
};
实现:
#include <sstream>
#include "Computer.h"
Computer::Computer(){
this->cpu = "i7";
}
string Computer::description(){
stringstream ret;
ret << "cpu:" << cpu;
return ret.str();
}
实现CPU升级
#include <iostream>
#include "Computer.h"
#include "ComputerService.h"
void update(Computer &computer) {
computer.cpu = "i9";
}
int main() {
Computer computer;
cout << computer.description() << endl;
update(computer);
cout << computer.description() << endl;
return 0;
}
② 友元类
通过一个类来实现对另一个类的数据成员和成员方法进行访问或修改
[例] 实现一个计算机服务类来实现对计算机的升级,杀毒,空间清理等功能
ComputerService.h
#pragma once
class Computer;
class ComputerService
{
public:
void update(Computer *computer);
void clean(Computer *computer);
void kill(Computer *computer);
};
Computer.h
#pragma once
#include <string>
#include "ComputerService.h"
using namespace std;
class Computer
{
public:
Computer();
string description();
private:
string cpu;
//可以对另一个类中的指定的成员函数声明为友元
// friend void ComputerService::update(Computer *computer);
friend class ComputerService; //声明为友元类
};
ComputerService.cpp
#include <iostream>
#include "ComputerService.h"
#include "Computer.h"`
void ComputerService::update(Computer *computer)
{
computer->cpu = "i9";
}
void ComputerService::clean(Computer * computer)
{
std::cout << "正在清理电脑[cpu:" << computer->cpu << "]" << endl;
}
void ComputerService::kill(Computer * computer)
{
std::cout << "正在进行电脑杀毒[cpu:" << computer->cpu << "]" << endl;
}
调用:
#include <iostream>
#include "Computer.h"
#include "ComputerService.h"
int main() {
Computer computer;
cout << computer.description() << endl;
ComputerService service;
service.update(&computer);
service.clean(&computer);
service.kill(&computer);
cout << computer.description() << endl;
return 0;
}
2.运算符重载
- 重载+运算符
方式一:使用成员函数
方式二:使用友元函数
[例] 实现一斤牛肉等于两斤猪肉,一斤羊肉等于三斤猪肉,将牛肉与羊肉相加
猪肉头文件
#pragma once
#include <string>
class Pork
{
public:
Pork(int weight = 0);
std::string description() const;
private:
int weight;
};
猪肉实现类:
#include <sstream>
#include "Pork.h"
Pork::Pork(int weight)
{
this->weight = weight;
}
std::string Pork::description() const
{
std::stringstream ret;
ret << "猪肉的重量为:" << weight << "斤";
return ret.str();
}
牛肉头文件
#pragma once
class Pork;
class Mutton;
class Beef
{
public:
Beef(int weight = 0);
//方式一: 使用成员函数来进行操作符重载
Pork operator+(Mutton mutton); //当前对象(牛肉)+ 羊肉,返回猪肉
Pork operator+(Beef beef); //当前对象(牛肉)+ 牛肉,返回猪肉
//方式二: 使用友元函数来实现操作符重载
friend Pork operator+(const Beef &beef, const Mutton &mutton);
friend Pork operator+(const Beef &beef1, const Beef &beef2);
private:
int weight;
};
牛肉实现类:
#include "Beef.h"
#include "Mutton.h"
#include "Pork.h"
Beef::Beef(int weight)
{
this->weight = weight;
}
Pork Beef::operator+(Mutton mutton)
{
int wei = this->weight * 2 + mutton.getWeight() * 3; //牛肉的价格是猪肉的2倍,羊肉的价格是猪肉的3倍
return Pork(wei); //返回猪肉
}
Pork Beef::operator+(Beef beef)
{
int wei = (this->weight + beef.weight) * 2; //牛肉的价格是猪肉的2倍,羊肉的价格是猪肉的3倍
return Pork(wei); //返回猪肉
}
羊肉头文件
#pragma once
class Mutton
{
public:
Mutton(int weight = 0);
int getWeight() const;
private:
int weight;
};
羊肉类的实现类
#include "Mutton.h"
Mutton::Mutton(int weight)
{
this->weight = weight;
}
int Mutton::getWeight() const
{
return this->weight;
}
main函数
#include <iostream>
#include "Beef.h"
#include "Mutton.h"
#include "Pork.h"
//友元函数来实现操作符重载
Pork operator+(const Beef &beef,const Mutton &mutton) {
int ret = beef.weight * 2 + mutton.getWeight() * 3;
return Pork(ret);
}
Pork operator+(const Beef &beef1, const Beef &beef2) {
int ret = (beef1.weight + beef2.weight) * 2;
return Pork(ret);
}
int main() {
Beef beef(100);
Beef beef2(160);
Mutton mutton(100);
std::cout << (beef + mutton).description() << std::endl;
std::cout << beef.operator+(mutton).description() << std::endl;
std::cout << (beef + beef).description() << std::endl;
Pork p;
p = beef + mutton;
std::cout << p.description() << std::endl;
p = beef + beef2;
std::cout << p.description() << std::endl;
return 0;
}
- 重载赋值运算符(=)
Boy创建boy1,boy2,boy3,把boy1的内容赋值给boy2,boy3
boy头文件:
#pragma once
#include <string>
using namespace std;
class Boy
{
public:
Boy(const char *name = NULL, int age = 0, int salary = 0, int darkHorse = 0);
~Boy();
string description();
/*
返回引用类型,便于连续赋值
参数使用引用类型, 可以省去一次拷贝
参数使用const, 便于保护实参不被破坏
*/
Boy& operator=(const Boy &boy);
private:
char *name;
int age;
int salary;
int darkHorse; //黑马系数
int id;
static int lastId;
};
boy实现类:
#include <sstream>
#include "Boy.h"
int Boy::lastId = 0;
Boy::Boy(const char * name, int age, int salary, int darkHorse)
{
if (!name) { //判断name是否为空
name = "无名";
}
this->name = new char[strlen(name)+1]; //申请内存来存储名字
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->darkHorse = darkHorse;
id = ++lastId;
}
Boy::~Boy()
{
delete name;
}
string Boy::description()
{
stringstream ret;
ret << "姓名:" << name << "\t年龄:" << age << "\t薪资:" << salary << "\t黑马系数" << darkHorse << "\tID:" <<id;
return ret.str();
}
Boy& Boy::operator=(const Boy & boy)
{
if (name) {
delete name;
}
name = new char[strlen(boy.name) + 1];
strcpy_s(name, strlen(boy.name) + 1, boy.name);
this->age = boy.age;
this->salary = boy.salary;
this->darkHorse = boy.darkHorse;
return *this;
}
main函数:
#include <iostream>
#include "Boy.h"
int main() {
Boy boy1("rock", 30, 20000, 3);
Boy boy2, boy3;
cout << boy1.description() << endl;
cout << boy2.description() << endl;
cout << boy3.description() << endl;
boy3 = boy2 = boy1;
cout << boy1.description() << endl;
cout << boy2.description() << endl;
cout << boy3.description() << endl;
return 0;
}
- 重载关系运算符(> < ==)
直接比较boy(即 boy1>boy2 / boy1<boy2 / boy1==boy2)
boy头文件:
#pragma once
#include <string>
using namespace std;
class Boy
{
public:
Boy(const char *name = NULL, int age = 0, int salary = 0, int darkHorse = 0);
~Boy();
string description();
bool operator>(Boy &boy);
bool operator<(Boy &boy);
bool operator==(Boy &boy);
private:
char *name;
int age;
int salary;
int darkHorse; //黑马系数
int id;
static int lastId;
int compareBoys() const;
};
boy实现类
#include <sstream>
#include "Boy.h"
int Boy::lastId = 0;
Boy::Boy(const char * name, int age, int salary, int darkHorse)
{
if (!name) { //判断name是否为空
name = "无名";
}
this->name = new char[strlen(name)+1]; //申请内存来存储名字
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->darkHorse = darkHorse;
id = ++lastId;
}
Boy::~Boy()
{
delete name;
}
string Boy::description()
{
stringstream ret;
ret << "姓名:" << name << "\t年龄:" << age << "\t薪资:" << salary << "\t黑马系数" << darkHorse << "\tID:" <<id;
return ret.str();
}
bool Boy::operator>(Boy & boy)
{
if (this->compareBoys() > boy.compareBoys()) {
return true;
}
else {
return false;
}
}
bool Boy::operator<(Boy & boy)
{
if (this->compareBoys() < boy.compareBoys()) {
return true;
}
else {
return false;
}
}
bool Boy::operator==(Boy & boy)
{
if (this->compareBoys() == boy.compareBoys()) {
return true;
}
else {
return false;
}
}
int Boy::compareBoys()const
{
int coefficient = salary + (100-age) * 10 + darkHorse * 100;
return coefficient;
}
main函数:
#include <iostream>
#include "Boy.h"
int main() {
Boy boy1("rock", 30, 20000, 3);
Boy boy2("martin", 25, 35000, 5);
if (boy1 > boy2) {
cout << "rock更值得选择" << endl;
}else if(boy1 < boy2){
cout << "martin更值得选择" << endl;
}
else if (boy1 == boy2) {
cout << "不分伯仲" << endl;
}
return 0;
}
- 重载关系运算符[ ]
对象访问使用:对象名[下标],下标使用字符串或数字
[例] 访问boy的age,boy[“age”] 或 boy[0]
boy头文件:
#pragma once
#include <string>
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARK_HORSE_KEY "darkHorse"
typedef enum
{
AGE,
SALARY,
DARK_HORSE,
POWER
} arr;
using namespace std;
class Boy
{
public:
Boy(const char *name = NULL, int age = 0, int salary = 0, int darkHorse = 0);
~Boy();
string description();
int operator[](string index); //下标运算符重载,输入字符串,返回年龄/薪资/黑马系数
int operator[](int index); //下标运算符重载,输入数字,返回年龄/薪资/黑马系数
private:
char *name;
int age;
int salary;
int darkHorse; //黑马系数
int id;
static int lastId;
int compareBoys() const;
};
boy类实现:
#include <sstream>
#include "Boy.h"
int Boy::lastId = 0;
Boy::Boy(const char * name, int age, int salary, int darkHorse)
{
if (!name) { //判断name是否为空
name = "无名";
}
this->name = new char[strlen(name)+1]; //申请内存来存储名字
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->darkHorse = darkHorse;
id = ++lastId;
}
Boy::~Boy()
{
delete name;
}
string Boy::description()
{
stringstream ret;
ret << "姓名:" << name << "\t年龄:" << age << "\t薪资:" << salary << "\t黑马系数" << darkHorse << "\tID:" <<id;
return ret.str();
}
int Boy::operator[](string index)
{
if (index == "age") {
return age;
}
else if (index == "salary") {
return salary;
}
else if (index == "darkHorse") {
return darkHorse;
}
else if (index == "power") {
return compareBoys();
}
else {
return -1;
}
}
int Boy::operator[](int index)
{
if (index == 0) {
return age;
}
else if (index == 1) {
return salary;
}
else if (index == 2) {
return darkHorse;
}
else if (index == 3) {
return compareBoys();
}
else {
return -1;
}
}
int Boy::compareBoys()const
{
int coefficient = salary + (100-age) * 10 + darkHorse * 100;
return coefficient;
}
main函数:
#include <iostream>
#include "Boy.h"
int main() {
Boy boy1("rock", 30, 20000, 3);
Boy boy2("martin", 25, 35000, 5);
cout << "年龄:" << boy1[AGE_KEY] << endl;
cout << "薪资:" << boy1[SALARY_KEY] << endl;
cout << "黑马系数:" << boy1[DARK_HORSE_KEY] << endl;
cout << "综合系数:" << boy1["power"] << endl;
cout << "-------------------------------" << endl;
cout << "年龄:" << boy2[AGE] << endl;
cout << "薪资:" << boy2[SALARY] << endl;
cout << "黑马系数:" << boy2[DARK_HORSE] << endl;
cout << "综合系数:" << boy2[POWER] << endl;
return 0;
}
- 重载输入、输出运算符(>> <<)
方式一:使用成员函数(没有实际意义,不建议使用)
方式二:使用友元函数
boy头文件:
#pragma once
#include <string>
using namespace std;
class Boy
{
public:
Boy(const char *name = NULL, int age = 0, int salary = 0, int darkHorse = 0);
~Boy();
string description();
//使用友元函数来实现输出输入运算符的重载
friend ostream &operator<<(ostream &os, const Boy &boy);
friend istream &operator>>(istream &is, Boy &boy);
private:
char *name;
int age;
int salary;
int darkHorse; //黑马系数
int id;
static int lastId;
int compareBoys() const;
};
boy类实现与前一节相同
main函数:
#include <iostream>
#include "Boy.h"
ostream &operator<<(ostream &os, const Boy &boy) {
os << "姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:" << boy.salary << "\t黑马系数" << boy.darkHorse;
return os;
}
istream &operator>>(istream &is, Boy &boy) {
string defName;
is >> defName >> boy.age >> boy.salary >> boy.darkHorse;
boy.name = new char[defName.length() + 1]; //申请内存空间
strcpy_s(boy.name, defName.length() + 1, defName.c_str()); //拷贝给boy的name
return is;
}
int main() {
Boy boy1("rock", 30, 20000, 3);
Boy boy2("martin", 25, 35000, 5);
cout << boy1 << endl;
cout << boy2 << endl;
return 0;
}
- 重载输入、输出运算符(>> <<)
① 普通类型转为类类型
[例] 只输入boy的薪资,boy的薪资将会被赋值
方法:创建一个构造函数
boy头文件:
#pragma once
#include <string>
using namespace std;
class Boy
{
public:
Boy(const char *name = NULL, int age = 0, int salary = 0, int darkHorse = 0);
~Boy();
string description();
//普通类型转换为类类型
Boy(int salary);
Boy(char* name);
private:
char *name;
int age;
int salary;
int darkHorse; //黑马系数
int id;
static int lastId;
};
boy类实现:
#include <sstream>
#include "Boy.h"
int Boy::lastId = 0;
Boy::Boy(const char * name, int age, int salary, int darkHorse)
{
if (!name) { //判断name是否为空
name = "无名";
}
this->name = new char[strlen(name)+1]; //申请内存来存储名字
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->darkHorse = darkHorse;
id = ++lastId;
}
Boy::~Boy()
{
delete name;
}
Boy::Boy(int salary)
{
const char *name = "无名";
this->name = new char[strlen(name) + 1]; //申请内存来存储名字
strcpy_s(this->name, strlen(name) + 1, name);
this->salary = salary;
this->age = 0;
this->darkHorse = 0;
id = ++lastId;
}
Boy::Boy(char * name)
{
this->name = new char[strlen(name) + 1]; //申请内存来存储名字
strcpy_s(this->name, strlen(name) + 1, name);
this->salary = 0;
this->age = 0;
this->darkHorse = 0;
id = ++lastId;
}
main函数:
#include <iostream>
#include "Boy.h"
ostream &operator<<(ostream &os, const Boy &boy) {
os << "姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:" << boy.salary << "\t黑马系数" << boy.darkHorse;
return os;
}
istream &operator>>(istream &is, Boy &boy) {
string defName;
is >> defName >> boy.age >> boy.salary >> boy.darkHorse;
boy.name = new char[defName.length() + 1]; //申请内存空间
strcpy_s(boy.name, defName.length() + 1, defName.c_str()); //拷贝给boy的name
return is;
}
int main() {
Boy b1(10000);
Boy b2("张分散");
cout << boy1.description() << endl;
cout << boy2.description() << endl;
return 0;
}
② 类类型转为普通类型
[例] 输入男生的所有信息,把这个对象赋值给男生类中的某个数据成员,可以改变数据成员的内容
boy头文件:
#pragma once
#include <string>
using namespace std;
class Boy
{
public:
Boy(const char *name = NULL, int age = 0, int salary = 0, int darkHorse = 0);
~Boy();
string description();
//类类型转换为普通类型
operator int() const;
operator char* () const;
private:
char *name;
int age;
int salary;
int darkHorse; //黑马系数
int id;
static int lastId;
};
boy类实现:
#include <sstream>
#include "Boy.h"
int Boy::lastId = 0;
Boy::Boy(const char * name, int age, int salary, int darkHorse)
{
if (!name) { //判断name是否为空
name = "无名";
}
this->name = new char[strlen(name)+1]; //申请内存来存储名字
strcpy_s(this->name, strlen(name) + 1, name);
this->age = age;
this->salary = salary;
this->darkHorse = darkHorse;
id = ++lastId;
}
Boy::~Boy()
{
delete name;
}
Boy::operator int() const
{
return compareBoys();
}
Boy::operator char*() const
{
return name;
}
main函数:
#include <iostream>
#include "Boy.h"
ostream &operator<<(ostream &os, const Boy &boy) {
os << "姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:" << boy.salary << "\t黑马系数" << boy.darkHorse;
return os;
}
istream &operator>>(istream &is, Boy &boy) {
string defName;
is >> defName >> boy.age >> boy.salary >> boy.darkHorse;
boy.name = new char[defName.length() + 1]; //申请内存空间
strcpy_s(boy.name, defName.length() + 1, defName.c_str()); //拷贝给boy的name
return is;
}
int main() {
Boy b3("张三",20,30000,4);
int power = b3;
char *name = b3;
cout << power << endl;
cout << name << endl;*/
return 0;
}
③ 类类型转为类类型
有一个新的类man 可以直接将boy对象赋值给man对象
方法:修改man的构造方法
man头文件:
#pragma once
#include <iostream>
using namespace std;
class Boy;
class Man
{
public:
Man(Boy &boy);
~Man();
friend ostream &operator<<(ostream &os, const Man &man);
private:
char *name;
int age;
int salary;
};
man实现类:
#include "Man.h"
#include "Boy.h"
Man::Man(Boy &boy)
{
// int length = strlen(boy.getName());
int length = strlen((char*)boy);
name = new char[length+1];
strcpy_s(name, length + 1, boy.getName());
age = boy[AGE];
salary = boy[SALARY];
}
Man::~Man()
{
delete name;
}
ostream &operator<<(ostream &os, const Man &man) {
os << "姓名:" << man.name << "\t年龄:" << man.age << "\t薪资:" << man.salary;
return os;
}
main函数:
#include <iostream>
#include "Boy.h"
ostream &operator<<(ostream &os, const Boy &boy) {
os << "姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:" << boy.salary << "\t黑马系数" << boy.darkHorse;
return os;
}
istream &operator>>(istream &is, Boy &boy) {
string defName;
is >> defName >> boy.age >> boy.salary >> boy.darkHorse;
boy.name = new char[defName.length() + 1]; //申请内存空间
strcpy_s(boy.name, defName.length() + 1, defName.c_str()); //拷贝给boy的name
return is;
}
int main() {
Boy boy("张三", 35, 50000, 4);
Man man(boy);
cout << boy << endl;
cout << man << endl;
return 0;
}
[注] = () [ ] -> 这四种运算符不能使用友元函数进行重载
不能被重载的运算符:
类别 | 符号 |
---|---|
成员访问 | . |
域运算 | :: |
内存长度运算 | sizeof |
三目运算 | ? : : |
预处理 | # |
可以被重载的运算符:
类别 | 符号 |
---|---|
双目运算符 | + - * / % |
关系运算符 | == != < <= > >= |
逻辑运算符 | 与 或 非 |
单目运算符 | +(正号) -(负号) *(指针) &(取地址) ++ – |
位运算 | & |
赋值运算符 | = += -= *= /= %= &= |
内存分配 | new delete new[ ] delete[ ] |
其他 | ( ) 函数调用 -> 成员访问 [ ] 下标 , 逗号 |
总结:项目13学的时间太久了,丧失了学习动力,中间有两个星期没能坚持,学习真的是一件孤独且容易放弃的事,后面的学习要继续努力!不因有效果而坚持,应坚持才产生效果,奥利给!!!