当前位置: 首页 > news >正文

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

 

其他文件不变

两种方式的区别

区别:

  1. 使用成员函数来实现运算符重载时,少写一个参数,因为第一个参数就是this指针。

两种方式的选择:

  1. 一般情况下,单目运算符重载,使用成员函数进行重载更方便(不用写参数)

  2. 一般情况下,双目运算符重载,使用友元函数

    #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指针)

注意:

同一个运算符重载, 不能同时使用两种方式来重载,会导致编译器不知道选择哪一个(二义性)

运算符重载的禁区和规则

  1. 为了防止对标准类型进行运算符重载,

    C++规定重载运算符的操作对象至少有一个不是标准类型,而是用户自定义的类型

    比如不能重载 1+2

    但是可以重载 cow + 2 和 2 + cow // cow是自定义的对象

    2.不能改变原运算符的语法规则, 比如不能把双目运算符重载为单目运

  2. 不能改变原运算符的优先级

    4.不能创建新的运算符,比如 operator*就是非法的, operator是可以的

  3. 不能对以下这四种运算符,使用友元函数进行重载

    = 赋值运算符,()函数调用运算符,[ ]下标运算符,->通过指针访问类成员

  4. 不能对禁止重载的运算符进行重载

不能被重载的运算符
成员访问.
域运算::
内存长度运算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是面向对象的&#xff0c;目的之一&#xff1a;封装 封装&#xff1a; 优点之一&#xff0c;就是安全。 缺点&#xff1a;在某些特殊的场合&#xff0c;不是很方便。 华为与IBM 40亿的咨询故事 IBM需要对华为各级部门做深度咨询分析&#xff0c; 为了提高咨询效率&a…...

DataWhale 机器学习夏令营第三期

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

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

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

python分析实战(4)--获取某音热榜

1. 分析需求 打开某音热搜&#xff0c;选择需要获取的热榜如图 查找包含热搜内容的接口返回如图 将url地址保存 2. 开发 定义请求头 headers {Cookie: 自己的cookie,Accept: application/json, text/plain, */*,Accept-Encoding: gzip, deflate,Host: www.douyin.com,…...

Java根据List集合中的一个字段对集合进行去重

利用HashSet 创建了一个HashSet用于存储唯一的字段值&#xff0c;并创建了一个新的列表uniqueList用于存储去重后的对象。遍历原始列表时&#xff0c;如果字段值未在HashSet中出现过&#xff0c;则将其添加到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

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

「Python|音视频处理|环境准备」如何在Windows系统下安装并配置音视频处理工具FFmpeg

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

软考高级架构师下篇-12层次式架构设计理论与实践

目录 1. 考情分析2. 层次式体系结构概述3. 表现层框架设计4. 中间层框架设计5. 数据访问层设计6. 数据架构规划与设计7. 物联网层次架构设计8. 前文回顾1. 考情分析 根据考试大纲,层次式架构设计理论与实践知识点会涉及单选题型(约占2~5分)和案例题(25分),本小时内容偏重于方…...

234. 回文链表

234. 回文链表 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* L…...

LInux之例行工作

目录 场景 单一执行例行任务 --- at&#xff08;一次性&#xff09; 安装 命令详解 语法格式 参数及作用 时间格式 案例 at命令执行过程分析 循环执行的例行性任务--crontab&#xff08;周期性&#xff09; crontd服务安装 linux 任务调度的工分类 crontab工作过程…...

C++,从“hello world“开始

一、"hello world" #inclue <iostream>using namespace std;int main() {cout << "hello world" << endl;return 0; } 1.1 #include&#xff1a;预处理标识 1.2 <iostream>&#xff1a;输入输出流类所在头文件 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访问工蜂报错&#xff1a; [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

总所周知&#xff0c;m1的mac不能录制桌面音频&#xff0c;obsstudio都不行。 最快的解决方法就是下载飞书&#xff1a; 登陆后新建直播/视频会议&#xff1a; 共享的时候选择下面的两个钩上去就好了...

数字人学习目录

数字人学习目录 百度PaddlePaddleHub图像风格迁移模型pp-tinypose模型 PaddleGANPaddleLitePaddleDetectionPP-TinyPose 人体骨骼关键点识别 PaddleSpeechVisualDLPaddleBobo TransformerWav2LibCLIPFFMpeg模型库数据集学习天地PythonJupyter Notebook Unity3DUE 百度Paddle P…...

PHP 房产网站系统Dreamweaver开发mysql数据库web结构php编程计算机网页项目

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

0基础入门代码审计-2 Fortify初探

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

qiiuzhiji4

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

构建 NodeJS 影院微服务并使用 docker 部署【01/4】

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

变频器和plc之间无线MODBUS通讯

在工业现场由PLC远程控制变频器的应用非常常见&#xff0c;如果挖沟布线不便或者变频器在移动设备上&#xff0c;那么采用无线通讯就是最佳方案。 这里我们选用最常用的三菱 FX2N PLC和三菱变频器为例&#xff0c;并结合日系plc专用无线通讯终端DTD435M来说明PLC与变频器之间的…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...