类和对象 (拷贝构造函数和运算符重载)上

类和对象 (拷贝构造函数和运算符重载)上

拷贝构造函数存在的原因及解决的 C 语言问题

1. 浅拷贝带来的问题

在 C 语言里,当对结构体或者数组进行拷贝操作时,执行的是浅拷贝。所谓浅拷贝,就是单纯地把一个对象的所有成员变量的值复制到另一个对象中。要是成员变量包含指针,那么仅仅是复制指针的值,也就是地址,并非复制指针所指向的内容。这就可能引发一些问题,比如多个指针指向同一块内存区域,在释放内存时就会出现重复释放的情况,进而导致程序崩溃。

下面是一个 C 语言的示例代码,展示了浅拷贝带来的问题:

#include <stdio.h>
#include <stdlib.h>typedef struct {int *data;int size;
} MyArray;// 初始化数组
void initArray(MyArray *arr, int size) {arr->size = size;arr->data = (int *)malloc(size * sizeof(int));for (int i = 0; i < size; i++) {arr->data[i] = i;}
}// 释放数组内存
void freeArray(MyArray *arr) {free(arr->data);
}int main() {MyArray arr1;initArray(&arr1, 5);// 浅拷贝MyArray arr2 = arr1;// 释放arr1的内存freeArray(&arr1);// 尝试访问arr2的数据,会导致未定义行为for (int i = 0; i < arr2.size; i++) {printf("%d ", arr2.data[i]);}return 0;
}

在这个例子中,arr2arr1 的浅拷贝,它们的 data 指针指向同一块内存区域。当释放 arr1 的内存后,arr2data 指针就变成了悬空指针,此时再访问 arr2.data 就会引发未定义行为。

在这里插入图片描述

2. C++ 拷贝构造函数的作用

C++ 的拷贝构造函数能够解决浅拷贝带来的问题。拷贝构造函数是一种特殊的构造函数(也就是和构造函数构成重载),当用一个已存在的对象来初始化另一个新对象时会被调用。在拷贝构造函数里,能够实现深拷贝,也就是复制指针所指向的内容,而不只是复制指针的值。

以下是一个 C++ 的示例代码,使用拷贝构造函数实现深拷贝:

#include <iostream>class MyArray {
private:int *data;int size;
public:// 构造函数MyArray(int size) : size(size) {data = new int[size];for (int i = 0; i < size; i++) {data[i] = i;}}// 拷贝构造函数,实现深拷贝MyArray(const MyArray& other) : size(other.size) {data = new int[size];//这里新开了一个大小和arr1中data数组相同的空间for (int i = 0; i < size; i++) {data[i] = other.data[i];}}// 析构函数~MyArray() {delete[] data;}// 打印数组元素void print() const {for (int i = 0; i < size; i++) {std::cout << data[i] << " ";}std::cout << std::endl;}
};int main() {MyArray arr1(5);MyArray arr2(arr1); // 自动调用拷贝构造函数arr1.print();arr2.print();return 0;
}

在这个例子中,MyArray 类的拷贝构造函数实现了深拷贝,确保 arr2arr1data 指针指向不同的内存区域,这样在释放内存时就不会出现重复释放的问题。

在这里插入图片描述

C 语言中的拷贝和 C++ 中的拷贝的区别
1. 拷贝方式
  • C 语言:主要采用浅拷贝,对于结构体和数组,只是简单地按位复制,不考虑指针指向的内容。
  • C++:默认情况下也是浅拷贝,但可以通过定义拷贝构造函数来实现深拷贝,从而避免浅拷贝带来的问题。
2. 语法和灵活性
  • C 语言:拷贝操作通常使用赋值语句或者自定义的拷贝函数,语法较为简单,但缺乏灵活性,需要手动处理内存管理。
  • C++:拷贝操作可以通过拷贝构造函数和赋值运算符重载来实现,语法更加灵活,能够自动处理内存管理,提高代码的安全性和可维护性。
3. 资源管理
  • C 语言:需要手动管理内存,在进行拷贝操作时容易出现内存泄漏和重复释放的问题。
  • C++:可以利用拷贝构造函数和析构函数来自动管理资源,减少内存管理的错误。

拷贝构造函数的特征

语法

拷贝构造函数的一般形式如下:

class ClassName {
public:// 拷贝构造函数ClassName(const ClassName& other) {// 拷贝操作}
};

在上述代码中,ClassName 是类名,other 是已存在对象的引用,通常使用 const 修饰,避免在拷贝过程中修改原对象。

调用场景

拷贝构造函数在以下几种常见情况下会被(自动)调用:

  • 用一个对象初始化另一个对象
ClassName obj1;
ClassName obj2(obj1); // 调用拷贝构造函数
  • 对象作为实参传递给函数
void func(ClassName obj) {// 函数体
}
ClassName obj;
func(obj); // 调用拷贝构造函数

我们前面说过了,形参是实参的拷贝,传参数的时候会对实参进行一个拷贝复制,复制出来的那个参数就是形参。

  • 函数返回对象
ClassName func() {ClassName obj;return obj; // 调用拷贝构造函数
}

要知道是, 当函数调用结束.函数里面所有开的空间都是要归还系统的,我们函数中return的变量也都是函数里面的。这里用上面的代码说明就是:返回的变量并不是函数中obj而是,obj这个变量的拷贝,也就是说,函数返回的变量是要返回变量的克隆体。明白吧,当这个变量类型是“某某类”(也就是自定义类型)的时候,这时候就会自动调用拷贝构造函数。

特征和性质(第一点我会画图解释)

  1. 参数类型为引用:拷贝构造函数的参数必须是引用类型,通常是 const 引用(const ClassName&)。如果使用值传递,会引发无限递归调用,因为值传递会再次调用拷贝构造函数来复制参数,从而导致栈溢出。
  2. 没有返回值:和其他构造函数一样,拷贝构造函数没有返回值,也不使用 void 声明。它的主要作用是初始化新对象,所以不需要返回任何值。
  3. 默认生成:若没有为类显式定义拷贝构造函数**(也就是我们没有写拷贝构造函数),编译器会自动生成一个默认的拷贝构造函数。(就类似构造函数一样,编译器会自动生成,但是编译器生成的只能处理一些非常非常简单类型)默认拷贝构造函数执行浅拷贝,即逐个复制对象的成员变量(比如日期类这些,我们就可以不用写拷贝构造函数,用编译器自动生成的就可以了)**。不过,当类包含动态分配的资源(如动态内存、文件句柄等)时,浅拷贝可能会引发问题,此时需要显式定义拷贝构造函数来实现深拷贝。
  4. 支持自定义操作:(这一点先不管)在显式定义的拷贝构造函数中,可以执行自定义的操作,比如深拷贝、更新计数器、记录日志等。这使得拷贝对象时可以根据类的具体需求进行特殊处理。
  5. 与析构函数和赋值运算符的关联:(这一点也先不管)遵循三 / 五 / 零法则。如果类需要显式定义析构函数、拷贝构造函数或拷贝赋值运算符中的任何一个,那么它很可能也需要显式定义另外两个。在 C++11 及以后,还需要考虑移动构造函数和移动赋值运算符。

在这里插入图片描述
在这里插入图片描述

运算符重载

运算符重载的基本概念

运算符重载本质上是一种函数,它的函数名由关键字operator和运算符组成。通过运算符重载,你能够让自定义类型的对象像内置类型对象那样使用运算符。

运算符重载存在的意义和解决的问题

1. 增强代码的可读性和可维护性

在处理自定义类型时,若没有运算符重载,你需要调用特定的成员函数来完成操作,这样会让代码显得冗长且难以阅读。运算符重载能让自定义类型的操作和内置类型操作保持一致,从而提高代码的可读性和可维护性。

2. 实现自定义类型的运算

内置运算符只能处理内置类型,而对于自定义类型,你可以通过运算符重载来定义适合它们的运算规则。

运算符重载的示例代码

以下是一个简单的示例,展示了如何重载>运算符来实现自定义类对象的加法:(用日期类来举例)

#include <iostream>
#include <cassert>
using std::cout;
using std::endl;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& dd){_year = dd._year;_month = dd._month;_day = dd._day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}bool operator>(const Date& other)//这是比较日期大小的{assert(_year>=1&&other._year>=1);assert(_month>=1 && _month<=12 && other._month>=1 && other._month<=12);assert(_day>=1 && other._month>=1);if(_year>other._year)return true;if(_year==other._year && _month>other._month)return true;if(_year==other._year && _month==other._month && _day>other._day)return true;return false;}bool operator==(const Date& other)//这是判断两日期是否相同的{assert(_year>=1&&other._year>=1);assert(_month>=1 && _month<=12 && other._month>=1 && other._month<=12);assert(_day>=1 && other._month>=1);if(_year==other._year &&_month==other._month &&_day==other._day)return true;return false;}private:int _year;int _month;int _day;
};int main() {Date d1;Date d2(2004,4,4);Date d3(d1);bool ret1= d2>d1;bool ret2= d1>d2;d2.Print();d1.Print();cout<<ret1<<endl<<ret2<<endl;bool ret3= d1==d3;d1.Print();d3.Print();cout<<ret3<<endl;return 0;
}

在这里插入图片描述

运算符重载的语法这里其实没多少东西:

返回类型 operator 运算符(参数列表) {// 函数体
}

它就是为了让你写的自定义类型比较的时候大家都能直观的看懂,不用费劲吧咧的想一个函数名。

其中,返回类型 是运算符重载函数的返回值类型,operator 是关键字,运算符 是要重载的运算符,参数列表 是传递给运算符函数的参数。对于二元运算符,参数通常是另一个操作数;对于一元运算符,通常没有显式参数。

运算符重载我们一般都写在类里面,为啥呢?因为成员变量绝大多数的时候都是私有的,你在类外定义函数虽然也可以,但是你要额外的写几个获取成员变量的函数,就是那些什么int getx()什么的。当然了,你也可以声明为友元函数,但是其实也没必要。所以为了方便,我们一般直接在类里面定义运算符重载,那么类里面定义的就属于成员函数

二元运算符

二元运算符需要两个操作数才能完成运算,像 +-*/ 这类。当使用成员函数重载二元运算符时,该函数是类的一个成员,而对象自身会隐式地作为运算符的左操作数,所以参数列表里通常只需传入另一个操作数(右操作数)。

别忘了,我们前面说过this指针就是其中的一个隐藏参数,所以类里面的成员函数中其实都是有一个隐藏参数的,所以在这里,我们只需要传另一个参数就可以了。一元运算符同理。

一元运算符

一元运算符仅需一个操作数就能完成运算,例如 ++--! 等。当使用成员函数重载一元运算符时,对象自身会隐式地作为运算符的操作数,所以通常不需要显式的参数。

类外定义运算符重载

在 C++ 中,除了可以在类内定义运算符重载函数,也能在类外进行定义。类外定义运算符重载函数通常有两种情况,一种是普通的非成员函数,另一种是使用友元函数。下面为你详细介绍这两种方式。

普通非成员函数重载运算符

当使用普通非成员函数重载运算符时,需要将所有操作数作为参数传递给运算符函数(也就是说,该有几个参数就是几个参数)。因为非成员函数没有隐含的 this 指针,所以不能直接访问类的私有成员,除非类提供了相应的公有访问函数。

友元函数重载运算符(这个先不管)

若运算符重载函数需要访问类的私有成员,可将其声明为类的友元函数。友元函数虽然不是类的成员函数,但它可以访问类的私有和保护成员。

运算符重载的优先级和结合性

在 C++ 中,运算符重载时,其优先级和结合性是由所重载的运算符本身决定的,而非由重载函数的定义决定。也就是说,重载后的运算符会保持其在原生运算符中的优先级和结合性。

优先级

运算符优先级规定了在一个表达式中不同运算符执行的先后顺序。例如,乘法运算符 * 的优先级高于加法运算符 +,所以在表达式 2 + 3 * 4 中,会先计算 3 * 4,再将结果与 2 相加。当你重载这些运算符时,它们的优先级依然保持不变。

结合性

结合性决定了相同优先级的运算符在表达式中是从左到右还是从右到左进行计算。例如,加法运算符 + 是左结合的,在表达式 2 + 3 + 4 中,会先计算 2 + 3,再将结果与 4 相加;而赋值运算符 = 是右结合的,在表达式 a = b = c 中,会先将 c 的值赋给 b,再将 b 的值赋给 a。重载运算符时,结合性同样保持不变。

改变优先级和结合性

如果你想改变优先级和结合性,那就加()呗,2 + 3 * 4加上括号( 2 + 3 ) * 4优先级就改变了,结合性同理哈。

注意事项

  • 并不是所有运算符都可以重载,例如 .::?: 等运算符不能被重载。
  • 重载运算符时,其操作数的数量、优先级和结合性不能改变。
  • 重载运算符的目的是提高代码的可读性和可维护性,应该避免过度使用或滥用运算符重载。
  • 运算符重载和函数重载没有任何关系。

日期类的实现

前面我已经给大家实现了比较日期的大小,和判断是否相等。那么接下来就是我们实现一些对日期类有意义的运算符重载。什么叫有意义呢?有意义就是对现实生活有意义的,比如+=天数之后是什么日期,比如2025年4月29日+=1,结果就是2025年4月30日。明白没。实现+天数也可以的,不过不改变日期类本身,+=是改变被加数本身的嘛。

那哪些是没有意义的呢?你觉得一个日期*一个日期或者一个日期/一个日期,这样有啥作用不? 这个对现实世界是不是没啥作用?所以我们就没必要去写,我们写一下对现实世界有意义的就行。

这个计算我们没学运算符重载也可以写,运算符重载只是为了我们使用的时候看起来更简洁,更易懂一些,更直观,明白嘛?

#include <iostream>
#include <cassert>
using std::cout;
using std::endl;class Date
{
public:Date(int year = 2025, int month = 4, int day = 29){_year = year;_month = month;_day = day;}Date(const Date& dd){_year = dd._year;_month = dd._month;_day = dd._day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}bool operator>(const Date& other){assert(_year>=1&&other._year>=1);assert(_month>=1 && _month<=12 && other._month>=1 && other._month<=12);assert(_day>=1 && other._month>=1);if(_year>other._year)return true;if(_year==other._year && _month>other._month)return true;if(_year==other._year && _month==other._month && _day>other._day)return true;return false;}bool operator==(const Date& other){assert(_year>=1&&other._year>=1);assert(_month>=1 && _month<=12 && other._month>=1 && other._month<=12);assert(_day>=1 && other._month>=1);if(_year==other._year &&_month==other._month &&_day==other._day)return true;return false;}int monthday(){assert(_month>=1 && _month<=12);int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};if(_month==2 && ((_year%4==0 && _year%100!=0) || _year%400==0)){return 29;}else{return day[_month];}}Date& operator+=(int day){_day+=day;while (_day>monthday()){_day-=monthday();_month+=1;if(_month>12){_year+=1;_month=1;}}return *this;}Date operator+(int day){Date tmp(*this);tmp+=day;return tmp;}
private:int _year;int _month;int _day;
};int main() {Date d1;Date d2=d1+100;d1.Print();d2.Print();return 0;
}

这里新增了一个运算符+和运算符+=的重载,逻辑其实很简单,需要注意一下主要是:

在这里插入图片描述
在这里插入图片描述

赋值运算符=重载

这个运算符重载有点特殊,不过不难理解。这里直接以日期类举例://运行一遍代码再往下看

class Date
{
public:Date(int year = 2025, int month = 4, int day = 29){_year = year;_month = month;_day = day;}Date(const Date& dd){_year = dd._year;_month = dd._month;_day = dd._day;}Date& operator=(const Date& other){if (this != &other){_year=other._year;_month=other._month;_day=other._day;}return *this;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main() {Date d1;Date d2(1999,9,9);d2.Print();d2=d1;d2.Print();return 0;
}

在这里插入图片描述

区别

1. 调用时机不同
  • 拷贝构造函数:在创建新对象时,使用另一个同类型的对象来初始化它时调用。常见的调用场景包括用一个对象初始化另一个对象、对象作为实参传递给函数、函数返回对象等。
class MyClass {
public:MyClass(const MyClass& other) {// 拷贝操作}
};MyClass obj1;
MyClass obj2(obj1); // 调用拷贝构造函数
  • 赋值运算符重载:在对象已经创建后,将一个对象的值赋给另一个对象时调用。
class MyClass {
public:MyClass& operator=(const MyClass& other) {if (this != &other) {// 赋值操作}return *this;}
};MyClass obj1, obj2;
obj1 = obj2; // 调用赋值运算符重载
2. 语法形式不同
  • 拷贝构造函数:是一种特殊的构造函数,没有返回值,参数通常是 const 引用。
MyClass(const MyClass& other);
  • 赋值运算符重载:是一个成员函数,返回值通常是对象的引用(MyClass&),以支持连续赋值操作,参数也通常是 const 引用。
MyClass& operator=(const MyClass& other);
3. 处理自我赋值的方式不同

在赋值运算符重载中,需要考虑自我赋值的情况(即 obj = obj),并进行相应的处理,避免不必要的操作或错误。而拷贝构造函数不会涉及自我赋值的问题,因为它是在创建新对象时调用的。

MyClass& operator=(const MyClass& other) {if (this != &other) {// 避免自我赋值,进行赋值操作}return *this;
}

未完待续.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/78976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python深度挖掘:openpyxl和pandas的使用详细

文章目录 一、Excel处理在数据分析中的重要性二、openpyxl基础与核心功能2.1 openpyxl简介与安装2.2 工作簿与工作表的基本操作创建新工作簿打开已有工作簿工作表操作 2.3 单元格操作详解基本单元格操作批量操作单元格特殊单元格操作 2.4 样式与格式设置字体样式对齐方式边框设…

Android Q允许低内存启用系统弹窗

如果SYSTEM_ALERT_WINDOW权限可用&#xff0c;则返回true。 *从Q开始&#xff0c;在低ram手机上禁用SYSTEM_ALERT_WINDOW。 vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/Utils.java public static boolean isSystemAlertWindowEnabled(Co…

taro小程序如何实现大文件(视频、图片)后台下载功能?

一、需求背景 1、需要实现小程序下载最大500M视频 2、同时需支持图片下载 3、退到其他页面再次回到当前页面时&#xff0c;下载进度也需要展示 二、实现步骤 1、在app.ts文件定义一个全局变量globalDownLoadData 2、写一个独立的下载hooks&#xff0c;代码如下&#xff08;…

BUUCTF——Online Tool

BUUCTF——Online Tool 进入靶场 <?phpif (isset($_SERVER[HTTP_X_FORWARDED_FOR])) {$_SERVER[REMOTE_ADDR] $_SERVER[HTTP_X_FORWARDED_FOR]; }if(!isset($_GET[host])) {highlight_file(__FILE__); } else {$host $_GET[host];$host escapeshellarg($host);$host e…

《解锁CSS Flex布局:重塑现代网页布局的底层逻辑》

网页布局作为用户体验的基石&#xff0c;其重要性不言而喻。从早期简单的表格布局&#xff0c;到后来基于浮动与定位的复杂尝试&#xff0c;网页布局技术始终在不断演进。而CSS Flex布局的出现&#xff0c;宛如一颗璀璨的新星&#xff0c;彻底革新了网页布局的设计理念与实践方…

4.28-4.29 Vue

基于数据渲染出用户看到的页面。 常用指令&#xff1a; click单击事件。 axios&#xff1a; 发出请求后&#xff0c;不会等待请求结束&#xff0c;而是继续进行下面的代码。

每日算法-250429

每日 LeetCode 题解 (2025-04-29) 大家好&#xff01;这是今天的 LeetCode 刷题记录&#xff0c;主要涉及几道可以使用贪心策略解决的问题。 2037. 使每位学生都有座位的最少移动次数 题目描述: 思路 贪心 解题过程 要使总移动次数最少&#xff0c;直观的想法是让每个学生…

yolov8+kalman 实现目标跟踪统计人流量

简述 最近接了毕业生的毕业设计题&#xff0c;想着帮帮忙&#xff0c;要使用机器视觉识别&#xff0c;追踪和逻辑统计的方式来统计人流&#xff0c;要求是满足下面特性 高精度&#xff1a;YOLOv8 提供高质量检测&#xff0c;卡尔曼滤波平滑跟踪。高效率&#xff1a;两者结合满…

Shopify网上商店GraphQL Admin接口查询实战

目录 一、Shopify网上商店 二、个人商店配置接口权限 三、PostMan调用接口测试 四、通过Java服务调用接口 一、Shopify网上商店 Shopify是由Tobi Ltke创办的加拿大电子商务软件开发商&#xff0c;总部位于加拿大首都渥太华&#xff0c;已从一家在咖啡店办公的 5人团队&…

【Tips】高效文献管理:Zotero 导入参考文献的多种方式详解

高效文献管理&#xff1a;Zotero 导入参考文献的多种方式详解 在学术研究中&#xff0c;高效管理参考文献是提升效率的关键。Zotero 作为一款强大的文献管理工具&#xff0c;提供了多种便捷的文献导入方式。以下结合文献题录完整性对比分析&#xff0c;为大家详细介绍 Zotero …

[AI]browser-use + web-ui 大模型实现自动操作浏览器

[AI]browser-use web-ui 大模型实现自动操作浏览器 介绍 官方地址&#xff1a;https://github.com/browser-use/web-ui browser-use主要作用是将 AI Agent 与浏览器链接起来从而实现由 AI 驱动的浏览器自动化。今天会给大家介绍如何通过browser-use web-ui来搭建并操作browse…

Springboot请求静态资源时,request.getServletPath() 返回error

大家好&#xff0c;我是 程序员码递夫。 SpringBoot请求静态资源时&#xff0c;request.getServletPath() 返回error&#xff0c; 明明我的目录文件是存在的怎么就报错了呢&#xff1f; 如我请求 http://127.0.0.1:9090/Hanfu/upload/1647161536390.png 通常是因为请求的资…

在开发板上如何处理curl: (60) SSL certificate problem

目录 引言 问题解析 解决方法 跳过证书验证 采用证书认证 结语 引言 最近一直推荐学生们在课程实验中使用curl及其libcurl。curl 是一个强大的命令行工具&#xff0c;用于在命令行中进行数据传输。它支持多种协议&#xff0c;如 HTTP、HTTPS、FTP、FTPS、SCP、SFTP 等。…

CSRF请求伪造

该漏洞主要是关乎于用户&#xff0c;告诫用户不可乱点击链接&#xff0c;提升自我防范&#xff0c;才能不落入Hacker布置的陷阱&#xff01; 1. cookie与session 简单理解一下两者作用 1.1. &#x1f36a; Cookie&#xff1a;就像超市的会员卡 存储位置&#xff1a;你钱包里…

Python循环与遍历详解:从入门到进阶

在Python编程中&#xff0c;循环和遍历是最基础但极其重要的知识点。理解并掌握这部分内容&#xff0c;是编写高效、清晰代码的前提。本文将从for循环和while循环的基本语法出发&#xff0c;逐步深入探讨range、enumerate、zip、列表推导式、字典遍历等Python中常见的遍历技巧&…

Python-MCPServer开发

Python-MCPServer开发 使用FastMCP开发【SSE模式的MCPServer】&#xff0c;熟悉【McpServer编码过程】【McpServer调试方法】 1-核心知识点 1-熟悉【SSE模式的MCPServer】开发2-熟悉【stdio模式的MCPServer】开发3-熟悉【启动MCPServer】的三种方式 3.1-直接启动:python mcp_s…

高级项目管理

在信息系统项目管理工作中&#xff0c;组织管理者和项目管理者&#xff0c;有时还会面临多项目的管理&#xff0c;或组织级的项目管理、项目的量化管理等课题。 其中&#xff0c;项目集管理、项目组合管理和组织级项目管理&#xff0c;为多项目管理和组织级管理提供有效指导&a…

tarjan缩点+强联通分量

【模板】缩点https://www.luogu.com.cn/problem/P3387 首先我们要理解这道题为什么要用缩点 题目说的是有向图&#xff0c;如果无环的话就可以用DP来解决了 由于可以走重复的点&#xff0c;所以一个环上的点可以看成是一个点&#xff0c;它的点权就等于该环上所有点的点权之…

OSCP:获取全交互式 Windows 反向 Shell

简介 在本文中&#xff0c;我们将探讨获取完全交互式 Windows 反向 Shell 的各种方法&#xff0c;从利用内置工具到采用先进技术以获得更好的控制和功能。 通过 Invoke-ConPtyShell 我获取完全交互式 Windows 反向 Shell 的首选方法是通过 Invoke-ConPtyShell 脚本。当 Wind…

免费超好用的电脑操控局域网内的手机(多台,无线)

使用 第一步 解压QtScrcpy压缩包&#xff0c;并运行QtScrcpy.exe 第二步 2.1 手机开启开发者模式&#xff08;设置>关于本机>版本信息>连点10下“版本号”&#xff09; 2.2 开启 USB调试 和 无线调试&#xff08;设置>开发者选项> USB调试 无线调试&#xf…