類和對象 (拷貝構造函數和運算符重載)上

類和對象 (拷貝構造函數和運算符重載)上

拷貝構造函數存在的原因及解決的 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.pswp.cn/bicheng/78976.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78976.shtml
英文地址,請注明出處:http://en.pswp.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…