c++ 友元 运算符重载详解
友元
c++是面向对象的,目的之一:封装
封装:
优点之一,就是安全。
缺点:在某些特殊的场合,不是很方便。
华为与IBM 40亿的咨询故事
IBM需要对华为各级部门做深度咨询分析,
为了提高咨询效率,由任正非直接授权,直接获取各部门的所有权限。
使用前提:
某个类需要实现某种功能,但是这个类自身,因为各种原因,无法自己实现。
需要借助于“外力”才能实现。
友元函数
使用全局函数作为友元函数
需求:
计算机和计算机的升级
Computer.h
#pragma once
#include <string>
class Computer
{
public:Computer();
// 使用全局函数作为友元函数 友元函数可以访问类的所有数据成员friend void upgrade(Computer* computer);
std::string description();
private:std::string cpu; //CPU芯片
};
computer.cpp
#include "Computer.h"
#include <sstream>
Computer::Computer()
{cpu = "i7";
}
std::string Computer::description()
{std::stringstream ret;ret << "CPU:" << cpu;return ret.str();
}
main.cpp
#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include "Computer.h"
void upgrade(Computer* computer) {computer->cpu = "i9"; //直接访问对象的私有数据成员!!!
}
int main(void) {Computer shanxing;std::cout << shanxing.description() << std::endl;upgrade(&shanxing);
std::cout << shanxing.description() << std::endl;
system("pause");return 0;
}
使用类的成员函数作为友元函数
需求:
计算机和计算机的升级
computer.h
#pragma once
#include <string>
#include <iostream>
#include <sstream>
#include "Computerservice.h"
using namespace std;
class Computer
{
public:Computer();string description();friend void Computerservice::upgrade(Computer* computer);//friend void upgrade(Computer* computer);//把外部的全局函数申明为这个类的友元函数
private:string cpu;};
computerservice.h
#pragma once
class Computer;
class Computerservice
{
public:void upgrade(Computer* computer);
};
computer.cpp
#include "Computer.h"
Computer::Computer()
{this->cpu = "i7";
}
string Computer::description()
{stringstream des;des << "CPU" << cpu;return des.str();
}
computerservice.cpp
#include "Computerservice.h"
#include "Computer.h"
void Computerservice::upgrade(Computer* computer)
{this->cpu = "i9";
}
main.cpp
#include "Computer.h"
#include <iostream>
#include "Computerservice.h"
//void upgrade(Computer * computer) {
// computer->cpu = "i9";
//}
int main(void) {Computer computer;Computerservice serviece;cout << computer.description() << endl;serviece.upgrade(&computer);cout << computer.description() << endl;return 0;
}
功能上,这两种形式,都是相同,应用场合不同。
一个是,使用普通的全局函数,作为自己的朋友,实现特殊功能。
一个是,使用其他类的成员函数,作为自己的朋友,实现特殊功能。
友元类
友元类的作用
如果把A类作为B类的友元类,
那么A类的所有成员函数【在A类的成员函数内】,就可以直接访问【使用】B类的私有成员。
即,友元类可以直接访问对应类的所有成员!!!
Demo
Computer.h
#pragma once
#include <string>
#include <iostream>
#include <sstream>
#include "Computerservice.h"
using namespace std;
class ComputerService;class Computer
{
public:friend class Computerservice;Computer();string description();private:string cpu;};Computer.cpp#include "Computer.h"
#include "Computerservice.h"
Computer::Computer()
{this->cpu = "i7";
}string Computer::description()
{stringstream des;des << "CPU" << cpu;return des.str();}
ComputerService.h
#pragma once
class Computer;class Computerservice
{
public:void upgrade(Computer* computer);void clear(Computer* computer);void kill(Computer* computer);
};
ComputerService.cpp
#include "Computerservice.h"
#include "Computer.h"void Computerservice::upgrade(Computer* computer)
{computer->cpu = "i9";
}void Computerservice::clear(Computer* computer)
{cout << "正在对电脑执行清理[CPU:" << computer->cpu << "]" < endl;
}void Computerservice::kill(Computer* computer)
{cout << "杀毒" << endl;
}
main.cpp
#include "Computer.h"
#include <iostream>
#include "Computerservice.h"int main(void) {Computer computer;Computerservice serviece;cout << computer.description() << endl;serviece.upgrade(&computer);cout << computer.description() << endl;serviece.clear(&computer);serviece.kill(&computer);return 0;
}
使用注意
友元类,和友元函数,使用friend关键字进行声明即可,与访问权限无关,
所以,可以放在private/pulic/protected任意区域内。
万物可运算-运算符重载
为什么要使用运算符重载
C/C++的运算符,支持的数据类型,仅限于基本数据类型。
问题:一头牛+一头马 = ?(牛马神兽?)
一个圆 +一个圆 = ? (想要变成一个更大的圆)
一头牛 – 一只羊 = ? (想要变成4只羊,原始的以物易物:1头牛价值5只羊)
解决方案:使用运算符重载
运算符重载基本用法
方式1-使用成员函数重载运算符
使用成员函数重载运算符
需求: // 规则:
// 一斤牛肉:2斤猪肉
// 一斤羊肉:3斤猪肉
Cow.h
#pragma onceclass Pork;
class Goat;class Cow
{
public:Cow(int weight);// 参数此时定义为引用类型,更合适,避免拷贝Pork operator+(const Cow& cow); //同类型进行运算,很频繁Pork operator+(const Goat& goat); //不同类型进行运算,比较少见
private:int weight = 0;
};
Cow.cpp
#include "Cow.h"
#include "Pork.h"
#include "Goat.h"Cow::Cow(int weight)
{this->weight = weight;
}// 规则:
// 一斤牛肉:2斤猪肉
// 一斤羊肉:3斤猪肉
Pork Cow::operator+(const Cow &cow)
{int tmp = (this->weight + cow.weight) * 2;return Pork(tmp);
}Pork Cow::operator+(const Goat& goat)
{// 不能直接访问goat.weight//int tmp = this->weight * 2 + goat.weight * 3;int tmp = this->weight * 2 + goat.getWeight() * 3;return Pork(tmp);
}
Goat.cpp
#include "Goat.h"Goat::Goat(int weight) {this->weight = weight; }int Goat::getWeight(void) const {return weight; }
Goat.h
#pragma once class Goat { public:Goat(int weight);int getWeight(void) const; private:int weight = 0; };
Pork.h
#pragma once
#include <iostream>class Pork
{
public:Pork(int weight);std::string description(void);private:int weight = 0;
};
Pork.cpp
#include "Pork.h"
#include <sstream>Pork::Pork(int weight)
{this->weight = weight;
}std::string Pork::description(void)
{std::stringstream ret;ret << weight << "斤猪肉";return ret.str();
}
main.cpp
#include <iostream> #include "Pork.h" #include "Cow.h" #include "Goat.h"int main(void) {Cow c1(100);Cow c2(200);// 调用c1.operator+(c2);//相当于:Pork p = c1.operator+(c2);Pork p = c1 + c2;std::cout << p.description() << std::endl;Goat g1(100);p = c1 + g1;std::cout << p.description() << std::endl;system("pause");return 0; }
方式二 - 使用非成员函数【友元函数】重载运算符
Cow.h
#pragma onceclass Pork;
class Goat;class Cow
{
public:Cow(int weight);// 有友元函数实现运算符重载friend Pork operator+(const Cow& cow1, const Cow& cow2);friend Pork operator+(const Cow& cow1, const Goat& goat);
private:int weight = 0;
};
main.cpp
其他文件不变
两种方式的区别
区别:
-
使用成员函数来实现运算符重载时,少写一个参数,因为第一个参数就是this指针。
两种方式的选择:
-
一般情况下,单目运算符重载,使用成员函数进行重载更方便(不用写参数)
-
一般情况下,双目运算符重载,使用友元函数
#include <iostream> #include "Pork.h" #include "Cow.h" #include "Goat.h"Pork operator+(const Cow &cow1, const Cow &cow2) {int tmp = (cow1.weight + cow2.weight) * 2;return Pork(tmp); }Pork operator+(const Cow& cow1, const Goat& goat) {int tmp = cow1.weight * 2 + goat.getWeight() * 3;return Pork(tmp); }int main(void) {Cow c1(100);Cow c2(200);Goat g1(100);Pork p = c1 + c2;std::cout << p.description() << std::endl;p = c1 + g1; // 思考:如何实现:p = g1 + c1;std::cout << p.description() << std::endl;system("pause");return 0; }
更直观
方便实现a+b和b+a相同的效果,成员函数方式无法实现。
例如: 100 + cow; 只能通过友元函数来实现
cow +100; 友元函数和成员函数都可以实现
特殊情况:
(1) = () [ ] -> 不能重载为类的友元函数!!!(否则可能和C++的其他规则矛盾),只能使用成员函数形式进行重载。
(2)如果运算符的第一个操作数要求使用隐式类型转换,则必须为友元函数(成员函数方式的第一个参数是this指针)
注意:
同一个运算符重载, 不能同时使用两种方式来重载,会导致编译器不知道选择哪一个(二义性)
运算符重载的禁区和规则
为了防止对标准类型进行运算符重载,
C++规定重载运算符的操作对象至少有一个不是标准类型,而是用户自定义的类型
比如不能重载 1+2
但是可以重载 cow + 2 和 2 + cow // cow是自定义的对象
2.不能改变原运算符的语法规则, 比如不能把双目运算符重载为单目运
不能改变原运算符的优先级
4.不能创建新的运算符,比如 operator*就是非法的, operator是可以的
不能对以下这四种运算符,使用友元函数进行重载
= 赋值运算符,()函数调用运算符,[ ]下标运算符,->通过指针访问类成员
不能对禁止重载的运算符进行重载
不能被重载的运算符
成员访问 | . |
---|---|
域运算 | :: |
内存长度运算 | sizeof |
三目运算 | ? : : |
预处理 | # |
可以被重载的运算符
双目运算符 | + - * / % |
---|---|
关系运算符 | == != < <= > >= |
逻辑运算符 | && || ! |
单目运算符 | +(正号) -(负号) *(指针) &(取地址) ++ -- |
位运算 | & | ~ ^ <<(左移) >>(右移) |
赋值运算符 | = += -= *= /= %= &= |= ^= <<= >>= |
内存分配 | new delete new[ ] delete[ ] |
其他 | ( ) 函数调用-> 成员访问 [ ] 下标, 逗号 |
重载运算符实例
重载赋值运算符=
Boy.h
#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& operator= (const Boy & boy);
private:char* name;int age;int salary;int darkHorse;//潜力系数unsigned int id;//编号static int LAST_ID;};
Boy.cpp
#include "Boy.h"
#include <string.h>
#include <sstream>
using namespace std;
int Boy::LAST_ID = 0;Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!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;this->id = ++LAST_ID;}Boy::~Boy()
{if (name) {delete name;}
}string Boy::description()
{stringstream des;des << "ID:" << id << "\t姓名:" << name << "\t年龄" << age << "\t薪资" << salary << "/t黑马系数" << darkHorse;return des.str();
}Boy& Boy::operator=(const Boy& boy)
{// TODO: 在此处插入 return 语句if (name) {delete name;}this->name = new char[strlen(boy.name) + 1];strcpy_s(this->name, strlen(boy.name) + 1,boy.name);this->age = boy.age;this->darkHorse = boy.darkHorse;this->salary = boy.salary;//this->idreturn *this;//返回这个对象}
Main.cpp
#include <iostream>
#include "boy.h"int main(void) {Boy boy1("lucifer", 16, 10000, 10);Boy boy2, boy3;std::cout << boy1.description() << std::endl;std::cout << boy2.description() << std::endl;std::cout << boy3.description() << std::endl;boy3 = boy2 = boy1;std::cout << boy2.description() << std::endl;std::cout << boy3.description() << std::endl;system("pause");return 0;
}
重载运算符> < ==
Boy.h 的方法加入
public: bool operator>(const Boy& boy);bool operator<(const Boy& boy);bool operator==(const Boy& boy);
private:int power() const; //综合能力值
Boy.cpp
bool Boy::operator>(const Boy& boy)
{// 设置比较规则:// 薪资 * 黑马系数 + (100-年龄)*100if (power() > boy.power()) {return true;}else {return false;}
}bool Boy::operator<(const Boy& boy)
{if (power() < boy.power()) {return true;}else {return false;}
}bool Boy::operator==(const Boy& boy)
{if (power() == boy.power()) {return true;}else {return false;}
}
下标运算符重载[ ]
Boy.h
#pragma once
#include <string>class Boy
{
public:Boy(const char* name=NULL, int age=0, int salary=0, int darkHorse=0);~Boy();Boy& operator=(const Boy& boy);bool operator>(const Boy& boy);bool operator<(const Boy& boy);bool operator==(const Boy& boy);int operator[](std::string index);int operator[](int index);std::string description(void);
private:char* name;int age;int salary;int darkHorse; //黑马值,潜力系数unsigned int id; // 编号static int LAST_ID;int power() const; //综合能力值
};
Boy.cpp
#include "boy.h"
#include <string.h>
#include <sstream>int Boy::LAST_ID = 0; //初始值是0Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!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;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name) {delete name;}
}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;//this->id = boy.id; //根据需求来确定是否要拷贝idreturn *this;
}bool Boy::operator>(const Boy& boy)
{// 设置比较规则:// 薪资 * 黑马系数 + (100-年龄)*100if (power() > boy.power()) {return true;}else {return false;}
}bool Boy::operator<(const Boy& boy)
{if (power() < boy.power()) {return true;}else {return false;}
}bool Boy::operator==(const Boy& boy)
{if (power() == boy.power()) {return true;}else {return false;}
}int Boy::operator[](std::string index)
{if (index == "age") {return age;}else if (index == "salary") {return salary;}else if (index == "darkHorse") {return darkHorse;}else if (index == "power") {return power();}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 power();}else {return -1;}
}std::string Boy::description(void)
{std::stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"<< salary << "\t黑马系数:" << darkHorse;return ret.str();
}int Boy::power() const
{// 薪资* 黑马系数 + (100 - 年龄) * 1000int value = salary * darkHorse + (100 - age) * 100;return value;
}
main.cpp
#include <iostream>
#include "boy.h"int main(void) {Boy boy1("Rock", 38, 58000, 5);Boy boy2("Jack", 25, 50000, 10);std::cout << "age:" << boy1["age"] << std::endl;std::cout << "salary:" << boy1["salary"] << std::endl;std::cout << "darkHorse:" << boy1["darkHorse"] << std::endl;std::cout << "power:" << boy1["power"] << std::endl;std::cout << "[0]:" << boy1[0] << std::endl;std::cout << "[1]:" << boy1[1] << std::endl;std::cout << "[2]:" << boy1[2] << std::endl;std::cout << "[3]:" << boy1[3] << std::endl;system("pause");return 0;
}
输入输出的重载<< >>
为了更方便的实现复杂对象的输入和输出。
方式1(使用成员函数)
不推荐,该方式没有实际意义
Boy.h
#pragma once
#include <string>
#include <iostream>using namespace std;class Boy
{
public:Boy(const char* name = NULL, int age = 0, int salary = 0, int darkHorse = 0);~Boy();Boy& operator=(const Boy& boy);bool operator>(const Boy& boy);bool operator<(const Boy& boy);bool operator==(const Boy& boy);int operator[](std::string index);int operator[](int index);ostream& operator<<(ostream& os) const;std::string description(void);private:char* name;int age;int salary;int darkHorse; //黑马值,潜力系数unsigned int id; // 编号static int LAST_ID;int power() const; //综合能力值
};
boy.cpp
#include "boy.h"
#include <string.h>
#include <sstream>int Boy::LAST_ID = 0; //初始值是0Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!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;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name) {delete name;}
}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;//this->id = boy.id; //根据需求来确定是否要拷贝idreturn *this;
}bool Boy::operator>(const Boy& boy)
{// 设置比较规则:// 薪资 * 黑马系数 + (100-年龄)*100if (power() > boy.power()) {return true;}else {return false;}
}bool Boy::operator<(const Boy& boy)
{if (power() < boy.power()) {return true;}else {return false;}
}bool Boy::operator==(const Boy& boy)
{if (power() == boy.power()) {return true;}else {return false;}
}int Boy::operator[](std::string index)
{if (index == "age") {return age;}else if (index == "salary") {return salary;}else if (index == "darkHorse") {return darkHorse;}else if (index == "power") {return power();}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 power();}else {return -1;}
}ostream& Boy::operator<<(ostream& os) const
{os << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"<< salary << "\t黑马系数:" << darkHorse;return os;
}std::string Boy::description(void)
{std::stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"<< salary << "\t黑马系数:" << darkHorse;return ret.str();
}int Boy::power() const
{// 薪资* 黑马系数 + (100 - 年龄) * 1000int value = salary * darkHorse + (100 - age) * 100;return value;
}
mian.cpp
#include <iostream>
#include "boy.h"int main(void) {Boy boy1("Rock", 38, 58000, 5);Boy boy2("Jack", 25, 50000, 10);// 调用: boy1.operator<<(cout);boy1 << cout;// 先调用 boy1.operator<<(cout)// 再调用 boy2.operator<<(cout)boy2 << (boy1 << cout);system("pause");return 0;
}
使用取来不方便
方式二(使用友元函数)
Boy.h
#pragma once
#include <string>
#include <iostream>#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARK_HORSE_KEY "darkHorse"
#define POWER_KEY "power"typedef enum {AGE,SALARY,DARK_HORSE,POWER
}BOY_KEY_TYPE;using namespace std;class Boy
{
public:Boy(const char* name = NULL, int age = 0, int salary = 0, int darkHorse = 0);~Boy();Boy& operator=(const Boy& boy);bool operator>(const Boy& boy);bool operator<(const Boy& boy);bool operator==(const Boy& boy);// 下标运算符的重载int operator[](std::string index);int operator[](int index);// 该方式不适合//ostream& operator<<(ostream& os) const;friend ostream& operator<<(ostream& os, const Boy& boy);friend istream& operator>>(istream& is, Boy& boy);std::string description(void);
private:char* name;int age;int salary;int darkHorse; //黑马值,潜力系数unsigned int id; // 编号static int LAST_ID;int power() const; //综合能力值
};
Boy.cpp
#include "boy.h"
#include <string.h>
#include <sstream>int Boy::LAST_ID = 0; //初始值是0Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!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;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name) {delete name;}
}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;//this->id = boy.id; //根据需求来确定是否要拷贝idreturn *this;
}bool Boy::operator>(const Boy& boy)
{// 设置比较规则:// 薪资 * 黑马系数 + (100-年龄)*100if (power() > boy.power()) {return true;}else {return false;}
}bool Boy::operator<(const Boy& boy)
{if (power() < boy.power()) {return true;}else {return false;}
}bool Boy::operator==(const Boy& boy)
{if (power() == boy.power()) {return true;}else {return false;}
}int Boy::operator[](std::string index)
{if (index == AGE_KEY) {return age;}else if (index == SALARY_KEY) {return salary;}else if (index == DARK_HORSE_KEY) {return darkHorse;}else if (index == POWER_KEY) {return power();}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 power();}else {return -1;}
}//ostream& Boy::operator<<(ostream& os) const
//{
// os << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"
// << salary << "\t黑马系数:" << darkHorse;
// return os;
//}std::string Boy::description(void)
{std::stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"<< salary << "\t黑马系数:" << darkHorse;return ret.str();
}int Boy::power() const
{// 薪资* 黑马系数 + (100 - 年龄) * 1000int value = salary * darkHorse + (100 - age) * 100;return value;
}
Main.cpp
#include <iostream>
#include "Boy.h"using namespace std;ostream& operator<<(ostream& os, const Boy& boy) {os << "ID:" << boy.id << "\t姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:"<< boy.salary << "\t黑马系数:" << boy.darkHorse;return os;
}istream& operator>>(istream& is, Boy& boy)
{string name2;is >> name2 >> boy.age >> boy.salary >> boy.darkHorse;boy.name = (char*)malloc((name2.length()+1) * sizeof(char));strcpy_s(boy.name, name2.length() + 1, name2.c_str());return is;
}int main(void) {Boy boy1("Rock", 38, 58000, 5);Boy boy2("Jack", 25, 50000, 10);cout << boy1 << endl;cin >> boy1;cout << boy1;system("pause");return 0;
}
重载-普通类型 =>类类型
调用对应的只有一个参数【参数的类型就是这个普通类型】的构造函数
需求: Boy boy1 = 10000; // 薪资 构造函数Boy(int);
Boy boy2 = "Rock" // 姓名 构造函数Boy(char *)
Boy.h
Boy(int salary);Boy(const char*);
Boy.cpp
Boy::Boy(int salary)
{const char* defaultName = "Unknow";this->name = new char[strlen(defaultName) + 1];strcpy_s(this->name, strlen(defaultName) + 1, defaultName);this->age =0;this->salary = salary;this->darkHorse = 0;this->id = ++LAST_ID;
}Boy::Boy(const char* name)
{this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = 0;this->salary = 0;this->darkHorse = 0;this->id = ++LAST_ID;
}
重载类类型=> 普通类型
调用特殊的运算符重载函数,类型转换函数,不需要写返回类型
类型转换函数:operator 普通类型 ( )
需求:
Boy boy1(“Rock”, 28, 10000, 5);int power = boy1; // power();char *name = boy1; // “Rock”
Boy.h
#pragma once
#include <string>
#include <iostream>#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARK_HORSE_KEY "darkHorse"
#define POWER_KEY "power"typedef enum {AGE,SALARY,DARK_HORSE,POWER
}BOY_KEY_TYPE;using namespace std;class Boy
{
public:Boy(const char* name , int age, int , int darkHorse);Boy(int salary);Boy(const char*);~Boy();Boy& operator=(const Boy& boy);bool operator>(const Boy& boy);bool operator<(const Boy& boy);bool operator==(const Boy& boy);// 下标运算符的重载int operator[](std::string index);int operator[](int index);//类型运算符重载 不需要返回类型operator char* ()const;operator int()const;// 该方式不适合//ostream& operator<<(ostream& os) const;friend ostream& operator<<(ostream& os, const Boy& boy);friend istream& operator>>(istream& is, Boy& boy);std::string description(void);
private:char* name;int age;int salary;int darkHorse; //黑马值,潜力系数unsigned int id; // 编号static int LAST_ID;int power() const; //综合能力值
};
Boy.cpp
#include "boy.h"
#include <string.h>
#include <sstream>int Boy::LAST_ID = 0; //初始值是0Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!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;this->id = ++LAST_ID;
}Boy::Boy(int salary)
{const char* defaultName = "Unknow";this->name = new char[strlen(defaultName) + 1];strcpy_s(this->name, strlen(defaultName) + 1, defaultName);this->age =0;this->salary = salary;this->darkHorse = 0;this->id = ++LAST_ID;
}Boy::Boy(const char* name)
{this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = 0;this->salary = 0;this->darkHorse = 0;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name) {delete name;}
}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;//this->id = boy.id; //根据需求来确定是否要拷贝idreturn *this;
}bool Boy::operator>(const Boy& boy)
{// 设置比较规则:// 薪资 * 黑马系数 + (100-年龄)*100if (power() > boy.power()) {return true;}else {return false;}
}bool Boy::operator<(const Boy& boy)
{if (power() < boy.power()) {return true;}else {return false;}
}bool Boy::operator==(const Boy& boy)
{if (power() == boy.power()) {return true;}else {return false;}
}int Boy::operator[](std::string index)
{if (index == AGE_KEY) {return age;}else if (index == SALARY_KEY) {return salary;}else if (index == DARK_HORSE_KEY) {return darkHorse;}else if (index == POWER_KEY) {return power();}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 power();}else {return -1;}
}Boy::operator char* () const
{return name;
}Boy::operator int() const
{return power();
}//ostream& Boy::operator<<(ostream& os) const
//{
// os << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"
// << salary << "\t黑马系数:" << darkHorse;
// return os;
//}std::string Boy::description(void)
{std::stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"<< salary << "\t黑马系数:" << darkHorse;return ret.str();
}int Boy::power() const
{// 薪资* 黑马系数 + (100 - 年龄) * 1000int value = salary * darkHorse + (100 - age) * 100;return value;
}
main.cpp
#include <iostream>
#include "Boy.h"using namespace std;ostream& operator<<(ostream& os, const Boy& boy) {os << "ID:" << boy.id << "\t姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:"<< boy.salary << "\t黑马系数:" << boy.darkHorse;return os;
}istream& operator>>(istream& is, Boy& boy)
{string name2;is >> name2 >> boy.age >> boy.salary >> boy.darkHorse;boy.name = (char*)malloc((name2.length() + 1) * sizeof(char));strcpy_s(boy.name, name2.length() + 1, name2.c_str());return is;
}int main(void) {Boy boy1("Rock", 38, 58000, 5);int power = boy1;char* name = boy1;system("pause");return 0;
}
类类型之间的转换 类类型A=> 类类型B
调用对应的只有一个参数【参数的类型就是类类型A】的构造函数
也可以使用类型转换函数,但是使用对应的构造函数更合适
实例:
把Boy类型,转换为Man类型
Boy.h
#pragma once
#include <string>
#include <iostream>
#include <ostream>
#include <istream>
#include <fstream>
#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARK_HORSE_KEY "darkHorse"
#define POWER_KEY "power"typedef enum {AGE,SALARY,DARK_HORSE,POWER
}BOY_KEY_TYPE;using namespace std;
class Man;
class Boy
{
public:Boy(const char* name , int age, int , int darkHorse);Boy(int salary);Boy(const char*);~Boy();char* getname()const;Boy& operator=(const Boy& boy);bool operator>(const Boy& boy);bool operator<(const Boy& boy);bool operator==(const Boy& boy);// 下标运算符的重载int operator[](std::string index)const;int operator[](int index)const;//类型运算符重载 不需要返回类型operator char* ()const;operator int()const;// 该方式不适合//ostream& operator<<(ostream& os) const;friend ostream& operator<<(ostream& os, const Boy& boy);friend istream& operator>>(istream& is, Boy& boy);std::string description(void);
private:char* name;int age;int salary;int darkHorse; //黑马值,潜力系数unsigned int id; // 编号static int LAST_ID;int power() const; //综合能力值
};//istream& operator>>(istream& is, Boy& boy);
//ostream& operator<<(ostream& os, const Boy& boy);
Boy.cpp
#include "Boy.h"
#include <string.h>
#include <sstream>int Boy::LAST_ID = 0; //初始值是0
ostream& operator<<(ostream& os, const Boy& boy) {os << "ID:" << boy.id << "\t姓名:" << boy.name << "\t年龄:" << boy.age << "\t薪资:"<< boy.salary << "\t黑马系数:" << boy.darkHorse;return os;
}istream& operator>>(istream& is, Boy& boy)
{string name2;is >> name2 >> boy.age >> boy.salary >> boy.darkHorse;boy.name = (char*)malloc((name2.length() + 1) * sizeof(char));strcpy_s(boy.name, name2.length() + 1, name2.c_str());return is;
}Boy::Boy(const char* name, int age, int salary, int darkHorse)
{if (!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;this->id = ++LAST_ID;
}Boy::Boy(int salary)
{const char* defaultName = "Unknow";this->name = new char[strlen(defaultName) + 1];strcpy_s(this->name, strlen(defaultName) + 1, defaultName);this->age =0;this->salary = salary;this->darkHorse = 0;this->id = ++LAST_ID;
}Boy::Boy(const char* name)
{this->name = new char[strlen(name) + 1];strcpy_s(this->name, strlen(name) + 1, name);this->age = 0;this->salary = 0;this->darkHorse = 0;this->id = ++LAST_ID;
}Boy::~Boy()
{if (name) {delete name;}
}char* Boy::getname() const
{return name;
}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;//this->id = boy.id; //根据需求来确定是否要拷贝idreturn *this;
}bool Boy::operator>(const Boy& boy)
{// 设置比较规则:// 薪资 * 黑马系数 + (100-年龄)*100if (power() > boy.power()) {return true;}else {return false;}
}bool Boy::operator<(const Boy& boy)
{if (power() < boy.power()) {return true;}else {return false;}
}bool Boy::operator==(const Boy& boy)
{if (power() == boy.power()) {return true;}else {return false;}
}int Boy::operator[](std::string index)const
{if (index == AGE_KEY) {return age;}else if (index == SALARY_KEY) {return salary;}else if (index == DARK_HORSE_KEY) {return darkHorse;}else if (index == POWER_KEY) {return power();}else {return -1;}
}int Boy::operator[](int index)const
{if (index == 0) {return age;}else if (index == 1) {return salary;}else if (index == 2) {return darkHorse;}else if (index == 3) {return power();}else {return -1;}
}Boy::operator char* () const
{return name;
}Boy::operator int() const
{return power();
}//ostream& Boy::operator<<(ostream& os) const
//{
// os << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"
// << salary << "\t黑马系数:" << darkHorse;
// return os;
//}std::string Boy::description(void)
{std::stringstream ret;ret << "ID:" << id << "\t姓名:" << name << "\t年龄:" << age << "\t薪资:"<< salary << "\t黑马系数:" << darkHorse;return ret.str();
}int Boy::power() const
{// 薪资* 黑马系数 + (100 - 年龄) * 1000int value = salary * darkHorse + (100 - age) * 100;return value;
}
Man.h
#pragma once
#include <iostream>
#include <ostream>
#include <istream>
#include <fstream>
class Boy;using namespace std;class Man
{
public:Man(const char* name, int age, int salary);Man(const Boy& boy);~Man();friend ostream&operator<<(ostream& os, const Man& man);friend istream&operator>>(istream& is, Man& man);private:int age;int salary;char* name;
};
//ostream& operator<<(ostream& os, const Man& man);
//istream& operator<<(istream& is, const Man& man);
Man.cpp
#include <iostream>
#include <fstream>
#include <ostream>
#include <istream>
#include "Boy.h"
#include "Man.h"
using namespace std;Man::Man(const char* name, int age, int salary)
{if (!name) {name = "未命名";}this->name = new char[strlen(name)+1];strcpy_s(this->name, strlen(name) + 1, name);this->age = age;this->salary = salary;
}Man::Man(const Boy& boy)
{int len = strlen((char*)boy) + 1;this->name = new char[len];strcpy_s(name, len, (char*)boy);age = boy[AGE];salary = boy[SALARY];}Man::~Man()
{delete name;
}ostream& operator<<(ostream& os, const Man& man)
{os <<"[男人]"<<"\t姓名:"<< man.name <<"\t年龄:" << man.age << "\t薪资:"<< man.salary;return os;
}istream& operator>>(istream& is, Man& man)
{// TODO: 在此处插入 return 语句string name2;is >> name2 >> man.salary;man.name = (char*)malloc((name2.length() + 1) * sizeof(char));strcpy_s(man.name, name2.length() + 1, name2.c_str());return is;
} //istream& operator>>(istream& is,const Man& man)
//{
// string name2;
// //is >> name2 >>man.salary ;
// is >> name2 >> man.salary;
// man.name = (char*)malloc((name2.length() + 1) * sizeof(char));
// strcpy_s(man.name, name2.length() + 1, name2.c_str());
// return is;
//}
Main.cpp
#include <iostream>
#include "Boy.h"
#include "Man.h"using namespace std;int main(void) {Boy boy("Rock", 38, 58000, 5);Man man = boy;cout << boy << endl;cout << man << endl;system("pause");return 0;
}
注意类型转换中的const const只能调用const方法 (operator函数)
常见错误总结-
const异常导致的BUG
小结:
const对象,只能调用对应的const方法
所以:
类的成员函数,如果已经确定不会修改任何数据成员,
那么,最好把这个成员函数,定义为const函数(在函数体的前面,参数列表的后面添加const)
main.cpp
#include <iostream>
#include "Human.h"
using namespace std;
int main()
{const Human lucifer("lucifer", 16, 10000);cout << lucifer[0] << endl;return 0;
}Human.cpp#include "Human.h"
#include <string.h>Human::Human(const char* name, int age, int salary) {int len = strlen(name) + 1;this->name = new char[len];strcpy_s(this->name, len, name);this->age = age;this->salary = salary;}Human::~Human()
{if (name) {delete name;}
}int Human::operator[](std::string index)const
{/*if (index == NAME) {}*/if (index == AGE_KEY) {return age;}else if (index == SALARY_KEY) {return salary;}else {return -1;}return 0;
}int Human::operator[](int index)
{if (index == AGE) {return age;}else if(index == SALARY){return salary;}else {return -1;}}
Human.h
#pragma once
#include <string>#define AGE_KEY "age"
#define SALARY_KEY "salary"
#define DARK_HORSE_KEY "darkHorse"
#define POWER_KEY "power"typedef enum {AGE,SALARY,POWER
}BOY_KEY_TYPE;class Human
{
public:Human(const char* name, int age,int salary);~Human();int operator[](std::string index)const;int operator[](int index);
private:char* name;int age;int salary;
};
如果此时调用main函数,那么此时的执行结果是
报错原因 const对象只能调用cosnt方法
operator= 的参数问题
赋值运算符的重载,应该使用这种方式:
Boy& operator=(const Boy &boy);
就是:参数要使用引用!
如果定义成:
Boy& operator=(const Boy *boy);
将会没有效果,编译器不会识别为赋值运算符的重载,
也就是:boy2 = boy1时不会调用这个函数
如果定义:
Boy& operator=(const Boy boy);
有效果,但是在调用时,会执行参数的传递:
比如:boy2 = boy1;
就会执行: boy2.operator=(boy1);
就会执行: const Boy boy = boy1;
就会执行: Boy类的赋值构造函数
有两个影响:
1) 浪费性能
2) 如果没有自定义的拷贝构造函数,而且这个类又有指针成员时,就会调用自动生成的拷贝构造函数,导致浅拷贝
如果析构函数中,对这个指针指向的内存做了释放,那就导致数据损坏或崩溃!
小结:
1)赋值·运算符的重载,一定要使用引用参数
2)如果一个类有指针成员,而且使用了动态内存分配,那么一定要定义自己的拷贝构造函数【要使用深拷贝】,避免调用自动生成的拷贝构造函数
因为自动生成的拷贝构造函数,是浅拷贝!
相关文章:

c++ 友元 运算符重载详解
友元 c是面向对象的,目的之一:封装 封装: 优点之一,就是安全。 缺点:在某些特殊的场合,不是很方便。 华为与IBM 40亿的咨询故事 IBM需要对华为各级部门做深度咨询分析, 为了提高咨询效率&a…...

DataWhale 机器学习夏令营第三期
DataWhale 机器学习夏令营第二期 学习记录一 (2023.08.18)1.赛题理解2.缺失值分析3. 简单特征提取4. 数据可视化离散变量离散变量分布分析 DataWhale 机器学习夏令营第三期 ——用户新增预测挑战赛 学习记录一 (2023.08.18) 已跑通baseline,换为lightgbm基线&#…...

回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现BES-LSSVM秃鹰搜索算法优化最小二乘支持向量机多输入单输出回归预测(多指标,多图&a…...

python分析实战(4)--获取某音热榜
1. 分析需求 打开某音热搜,选择需要获取的热榜如图 查找包含热搜内容的接口返回如图 将url地址保存 2. 开发 定义请求头 headers {Cookie: 自己的cookie,Accept: application/json, text/plain, */*,Accept-Encoding: gzip, deflate,Host: www.douyin.com,…...
Java根据List集合中的一个字段对集合进行去重
利用HashSet 创建了一个HashSet用于存储唯一的字段值,并创建了一个新的列表uniqueList用于存储去重后的对象。遍历原始列表时,如果字段值未在HashSet中出现过,则将其添加到HashSet和uniqueList中。 List<Person> originalList new Ar…...
(AtCoder Beginner Contest 315)
A.直接模拟即可 import random import sys import os import math from collections import Counter, defaultdict, deque from functools import lru_cache, reduce from itertools import accumulate, combinations, permutations from heapq import nsmallest, nlargest, h…...

API 接口选择那个?RESTful、GraphQL、gRPC、WebSocket、Webhook
大家好,我是比特桃。目前我们的生活紧紧地被大量互联网服务所包围,互联网上每天都有数百亿次API调用。API 是两个设备相互通讯的一种方式,人们在手机上每次指尖的悦动,背后都是 API 接口的调用。 本文将列举常见的一些 API 接口&…...

「Python|音视频处理|环境准备」如何在Windows系统下安装并配置音视频处理工具FFmpeg
本文主要介绍如何在Windows系统下安装并配置音视频处理工具FFmpeg,方便使用python进行音视频相关的下载或编辑处理。 文章目录 一、下载软件二、解压并配置三、验证安装 一、下载软件 首先要去 ffmpeg官网 下载软件包 由于上面直接下载的按钮是.tar.xz格式的。为了…...

软考高级架构师下篇-12层次式架构设计理论与实践
目录 1. 考情分析2. 层次式体系结构概述3. 表现层框架设计4. 中间层框架设计5. 数据访问层设计6. 数据架构规划与设计7. 物联网层次架构设计8. 前文回顾1. 考情分析 根据考试大纲,层次式架构设计理论与实践知识点会涉及单选题型(约占2~5分)和案例题(25分),本小时内容偏重于方…...
234. 回文链表
234. 回文链表 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* L…...

LInux之例行工作
目录 场景 单一执行例行任务 --- at(一次性) 安装 命令详解 语法格式 参数及作用 时间格式 案例 at命令执行过程分析 循环执行的例行性任务--crontab(周期性) crontd服务安装 linux 任务调度的工分类 crontab工作过程…...
C++,从“hello world“开始
一、"hello world" #inclue <iostream>using namespace std;int main() {cout << "hello world" << endl;return 0; } 1.1 #include:预处理标识 1.2 <iostream>:输入输出流类所在头文件 1.2.1 istream&a…...

/root/.ssh/config line 2: Bad protocol 2 host key algorithms ‘+ssh-rsa‘.
文章目录 1、问题2、查看openssh版本3、解决问题4、重新生成密钥5、查看是否可连接工蜂 1、问题 ssh访问工蜂报错: [rootlocalhost .ssh]# ssh -T gitgit.code.tencent.com /root/.ssh/config line 2: Bad protocol 2 host key algorithms ‘ssh-rsa’. 2、查看o…...

mac m1上系统内录内部声音的方法/无需安装Blackhole
总所周知,m1的mac不能录制桌面音频,obsstudio都不行。 最快的解决方法就是下载飞书: 登陆后新建直播/视频会议: 共享的时候选择下面的两个钩上去就好了...
数字人学习目录
数字人学习目录 百度PaddlePaddleHub图像风格迁移模型pp-tinypose模型 PaddleGANPaddleLitePaddleDetectionPP-TinyPose 人体骨骼关键点识别 PaddleSpeechVisualDLPaddleBobo TransformerWav2LibCLIPFFMpeg模型库数据集学习天地PythonJupyter Notebook Unity3DUE 百度Paddle P…...

PHP 房产网站系统Dreamweaver开发mysql数据库web结构php编程计算机网页项目
一、源码特点 PHP 房产网站系统是一套完善的WEB设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 源码 https://download.csdn.net/download/qq_41221322/88233553 论文 https://download…...

0基础入门代码审计-2 Fortify初探
0x01 序言 目前又加入一位新童鞋了,最近将会再加入cs相关的专栏,都是以基础为主,毕竟太复杂的东西,能看懂的人太少。 0x02 准备工具 1、Fortify 2、需要审计的源码 0x03 Fortify的简单使用 1、 1、在开始菜单栏中找到Audit Wo…...

qiiuzhiji4
本篇是从慧与离职后到2023年8月21日这段时间的经历 2023/7/31至2023/8/21 本篇初次写于2023年8月21日 从慧与离职后基本上就是在专心找工作了,但是有在这段时间找工作经历的人都明白,IT行业不复以往了。尤其是对于我这样的普通二本学历的人来说ÿ…...

构建 NodeJS 影院微服务并使用 docker 部署【01/4】
图片来自谷歌 — 封面由我制作 一、说明 构建一个微服务的电影网站,需要Docker、NodeJS、MongoDB,这样的案例您见过吗?如果对此有兴趣,您就继续往下看吧。 在本系列中,我们将构建一个 NodeJS 微服务,并使用…...

变频器和plc之间无线MODBUS通讯
在工业现场由PLC远程控制变频器的应用非常常见,如果挖沟布线不便或者变频器在移动设备上,那么采用无线通讯就是最佳方案。 这里我们选用最常用的三菱 FX2N PLC和三菱变频器为例,并结合日系plc专用无线通讯终端DTD435M来说明PLC与变频器之间的…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...

Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...

Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...

react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...