【C++游記】物種多樣——謂之多態

??

楓の個人主頁

你不能改變過去,但你可以改變未來

算法/C++/數據結構/C

Hello,這里是小楓。C語言與數據結構和算法初階兩個板塊都更新完畢,我們繼續來學習C++的內容呀。C++是接近底層有比較經典的語言,因此學習起來注定枯燥無味,西游記大家都看過吧~,我希望能帶著大家一起跨過九九八十一難,降伏各類難題,學會C++,我會盡我所能,以通俗易懂、幽默風趣的方式帶給大家形象生動的知識,也希望大家遇到困難不退縮,遇到難題不放棄,學習師徒四人的精神!!!故此得名【C++游記

?話不多說,讓我們一起進入今天的學習吧~~~??

一、多態的概念

多態(polymorphism)字面意思是“多種形態”,在C++中分為兩類:編譯時多態(靜態多態)運行時多態(動態多態)

1. 編譯時多態(靜態多態)

核心是“編譯期確定調用哪個函數”,主要通過函數重載函數模板實現。

原理:通過不同的參數類型/個數,編譯器在編譯階段就確定要調用的函數版本,無需運行時判斷。

// 函數重載示例(編譯時多態)
#include <iostream>
using namespace std;// 加法函數:int類型
int add(int a, int b) {return a + b;
}// 加法函數:double類型(重載)
double add(double a, double b) {return a + b;
}int main() {cout << add(1, 2) << endl;    // 編譯時確定調用int版本cout << add(1.5, 2.5) << endl;// 編譯時確定調用double版本return 0;
}

2. 運行時多態(動態多態)

核心是“運行期確定調用哪個函數”,即“同一個行為,傳入不同對象,產生不同結果”。

生活案例:
- 買票行為:普通人全價、學生打折、軍人優先
- 動物叫行為:貓“喵”、狗“汪汪”

// 動物叫示例(運行時多態)
#include <iostream>
using namespace std;class Animal {
public:// 虛函數:關鍵標志virtual void talk() const {cout << "動物叫" << endl;}
};class Cat : public Animal {
public:// 重寫虛函數virtual void talk() const override {cout << "(>^ω^<)喵" << endl;}
};class Dog : public Animal {
public:virtual void talk() const override {cout << "汪汪" << endl;}
};// 統一接口:接收基類引用
void letsHear(const Animal& animal) {animal.talk(); // 運行時確定調用哪個版本
}int main() {Cat cat;Dog dog;letsHear(cat); // 輸出:(>^ω^<)喵letsHear(dog); // 輸出:汪汪return 0;
}

注意:

本文重點講解運行時多態,因為它是C++面向對象的核心,也是面試高頻考點;編譯時多態相對簡單,日常開發中使用頻率也較低。

二、多態的定義及實現

2.1 多態的構成條件

要實現運行時多態,必須同時滿足以下兩個核心條件:

  • 條件1:必須通過基類的指針或引用調用虛函數
  • 條件2:被調用的函數必須是虛函數,且派生類必須對基類的虛函數完成重寫(覆蓋)

為什么必須用基類指針/引用?

因為只有基類的指針或引用才能“兼容”指向基類對象和派生類對象,普通基類對象無法做到這一點(會發生切片,丟失派生類特性)。

2.1.1 虛函數

虛函數是多態的“開關”,定義方式:在類成員函數前加virtual關鍵字。

// 虛函數定義示例
class Person {
public:// 虛函數:加virtual關鍵字virtual void BuyTicket() {cout << "買票-全價" << endl;}// 注意:非成員函數不能加virtual(編譯報錯)// virtual void func() {} // 錯誤:全局函數不能是虛函數
};class Student : public Person {
public:// 派生類虛函數:建議顯式加virtual(規范)virtual void BuyTicket() {cout << "買票-打折" << endl;}
};

注意:

1.virtual只能修飾類成員函數,不能修飾全局函數、靜態成員函數、構造函數;

2. 派生類的虛函數可以省略virtual(因為繼承后基類虛函數的“虛屬性”會保留),但不建議這樣寫,會降低代碼可讀性。

2.1.2 虛函數的重寫(覆蓋)

重寫(覆蓋)是指:派生類中有一個與基類完全相同的虛函數(返回值類型、函數名、參數列表必須完全一致),此時派生類的虛函數會“覆蓋”基類的虛函數。

// 虛函數重寫示例
#include <iostream>
using namespace std;class Person {
public:// 基類虛函數virtual void BuyTicket() {cout << "Person: 買票-全價" << endl;}
};class Student : public Person {
public:// 派生類重寫虛函數(返回值、函數名、參數列表完全一致)virtual void BuyTicket() override { // override關鍵字:檢測重寫是否正確cout << "Student: 買票-半價" << endl;}
};class Soldier : public Person {
public:// 派生類重寫虛函數virtual void BuyTicket() override {cout << "Soldier: 買票-優先" << endl;}
};// 統一接口:基類指針
void Func(Person* ptr) {ptr->BuyTicket(); // 運行時確定調用哪個版本
}int main() {Person ps;Student st;Soldier sr;Func(&ps);  // 輸出:Person: 買票-全價Func(&st);  // 輸出:Student: 買票-半價Func(&sr);  // 輸出:Soldier: 買票-優先return 0;
}

2.1.3 析構函數的重寫(面試重點)

析構函數的重寫是一個特殊場景:基類析構函數為虛函數時,派生類析構函數無論是否加virtual,都與基類析構函數構成重寫

原因:編譯器會將所有析構函數的名稱統一處理為destructor,因此即使派生類析構函數名與基類不同,也能構成重寫。

// 析構函數重寫的重要性(避免內存泄漏)
#include <iostream>
using namespace std;class A {
public:// 基類析構函數:加virtualvirtual ~A() {cout << "~A()" << endl;}
};class B : public A {
public:B() {_p = new int[10]; // 動態申請內存}// 派生類析構函數:無需顯式加virtual(但建議加)~B() override {delete[] _p; // 釋放內存cout << "~B(): 釋放了int數組" << endl;}private:int* _p;
};int main() {A* p1 = new A;A* p2 = new B;delete p1; // 輸出:~A()(正確)delete p2; // 輸出:~B(): 釋放了int數組 → ~A()(正確,無內存泄漏)return 0;
}

面試必問:為什么基類析構函數建議設計為虛函數?

如果基類析構函數不是虛函數,當用基類指針指向派生類對象并刪除時,只會調用基類析構函數,不會調用派生類析構函數,導致派生類中動態申請的內存無法釋放,造成內存泄漏

2.2 易混淆概念對比

C++中重載、重寫(覆蓋)、重定義(隱藏)是三個容易混淆的概念,這里用表格清晰對比:

概念定義作用范圍函數名參數列表返回值virtual關鍵字
重載同一作用域內的同名函數同一類相同不同可以不同無關
重寫(覆蓋)派生類重寫基類的虛函數基類與派生類相同相同相同(協變除外)基類必須有,派生類可省略
重定義(隱藏)派生類與基類同名函數(非重寫)基類與派生類相同可以相同/不同可以不同基類無virtual或參數不同
// 重載、重寫、重定義對比示例
#include <iostream>
using namespace std;class Base {
public:// 重載:同一類中,函數名相同,參數不同void func() {cout << "Base::func()" << endl;}void func(int x) {cout << "Base::func(int x)" << endl;}// 虛函數:可被重寫virtual void virtualFunc() {cout << "Base::virtualFunc()" << endl;}// 非虛函數:會被派生類重定義(隱藏)void nonVirtualFunc() {cout << "Base::nonVirtualFunc()" << endl;}
};class Derived : public Base {
public:// 重寫(覆蓋):重寫基類虛函數virtual void virtualFunc() override {cout << "Derived::virtualFunc()" << endl;}// 重定義(隱藏):與基類nonVirtualFunc同名,參數相同但基類無virtualvoid nonVirtualFunc() {cout << "Derived::nonVirtualFunc()" << endl;}// 重定義(隱藏):與基類func同名但參數不同void func(double x) {cout << "Derived::func(double x)" << endl;}
};int main() {Derived d;Base* b = &d;b->func();           // 調用Base::func()b->func(10);         // 調用Base::func(int x)b->virtualFunc();    // 調用Derived::virtualFunc()(重寫,多態)b->nonVirtualFunc(); // 調用Base::nonVirtualFunc()(非虛函數,不構成多態)d.func(3.14);        // 調用Derived::func(double x)d.Base::func();      // 顯式調用基類被隱藏的函數return 0;
}

三、純虛函數與抽象類

3.1 純虛函數

純虛函數是一種特殊的虛函數:在聲明時初始化為0,且沒有函數體。它的作用是強制派生類必須重寫該函數

// 純虛函數定義
class Shape {
public:// 純虛函數:=0表示沒有函數體virtual double area() const = 0; // 普通虛函數:可以有函數體virtual void printInfo() const {cout << "這是一個圖形" << endl;}
};

3.2 抽象類

含有純虛函數的類稱為抽象類(也叫接口類)。抽象類有以下特性:

  • 抽象類不能實例化對象(無法創建具體實例)
  • 抽象類的派生類必須重寫所有純虛函數,否則該派生類仍為抽象類
  • 抽象類可以定義普通成員函數和成員變量
  • 可以聲明抽象或引用(這是多態的基礎)
// 抽象類示例
#include <iostream>
using namespace std;// 抽象類:含有純虛函數
class Shape {
public:// 純虛函數:計算面積virtual double area() const = 0;// 純虛函數:計算周長virtual double perimeter() const = 0;// 普通成員函數void print() const {cout << "面積: " << area() << ", 周長: " << perimeter() << endl;}
};// 派生類:圓
class Circle : public Shape {
public:Circle(double r) : _radius(r) {}// 必須重寫所有純虛函數double area() const override {return 3.14 * _radius * _radius;}double perimeter() const override {return 2 * 3.14 * _radius;}private:double _radius; // 半徑
};// 派生類:矩形
class Rectangle : public Shape {
public:Rectangle(double w, double h) : _width(w), _height(h) {}// 必須重寫所有純虛函數double area() const override {return _width * _height;}double perimeter() const override {return 2 * (_width + _height);}private:double _width;  // 寬double _height; // 高
};// 多態應用:統一接口操作不同圖形
void showShapeInfo(const Shape& shape) {shape.print();
}int main() {// 錯誤:抽象類不能實例化對象// Shape shape; // 正確:可以聲明抽象類的指針/引用Circle circle(5.0);Rectangle rect(3.0, 4.0);showShapeInfo(circle); // 輸出:面積: 78.5, 周長: 31.4showShapeInfo(rect);   // 輸出:面積: 12, 周長: 14return 0;
}

抽象類的應用場景:

當我們需要定義一個基類,但不希望它被實例化,只作為派生類的接口規范時,就可以使用抽象類。例如:

  • 圖形類(Shape):派生類可以是圓形、矩形、三角形等
  • 動物類(Animal):派生類可以是貓、狗、鳥等
  • 設備類(Device):派生類可以是打印機、掃描儀、投影儀等

四、多態的底層原理

C++多態的底層是通過虛函數表(Virtual Table,簡稱vtable)虛表指針(vpointer,簡稱vptr)實現的。理解這一機制,能幫你更深入地掌握多態的本質。

4.1 虛函數表(vtable)

當一個類中含有虛函數時,編譯器會為該類創建一個虛函數表

  • 虛函數表是一個函數指針數組,存儲該類所有虛函數的地址
  • 每個含有虛函數的類只有一個虛函數表(所有對象共享)
  • 派生類會繼承基類的虛函數表,如果重寫了基類的虛函數,會用派生類自己的函數地址覆蓋虛表中對應的位置
  • 如果派生類有新的虛函數,會被添加到虛函數表的末尾

4.2 虛表指針(vptr)

每個含有虛函數的類的對象,都會有一個虛表指針(vptr)

  • 虛表指針是對象的第一個成員(存儲在對象內存的最前面)
  • 虛表指針指向該類的虛函數表
  • 對象創建時,編譯器會自動初始化vptr,使其指向相應的虛函數表

4.3 多態的實現過程

當通過基類指針/引用調用虛函數時,多態的實現過程如下:

  1. 通過基類指針/引用訪問對象的虛表指針(vptr)
  2. 通過vptr找到該對象所屬類的虛函數表(vtable)
  3. 在虛函數表中找到對應虛函數的地址
  4. 調用該地址指向的函數(即派生類重寫后的函數)
// 多態底層原理示例
#include <iostream>
using namespace std;class Base {
public:virtual void func1() { cout << "Base::func1()" << endl; }virtual void func2() { cout << "Base::func2()" << endl; }void func3() { cout << "Base::func3()" << endl; } // 非虛函數
private:int _b = 1;
};class Derived : public Base {
public:virtual void func1() override { cout << "Derived::func1()" << endl; }virtual void func3() { cout << "Derived::func3()" << endl; } // 新的虛函數
private:int _d = 2;
};int main() {Base b;Derived d;// 注意:以下輸出結果可能因編譯器不同而略有差異cout << "Base對象大小: " << sizeof(b) << endl;  // 輸出:8(4字節_b + 4字節vptr)cout << "Derived對象大小: " << sizeof(d) << endl;// 輸出:12(4字節_b + 4字節_d + 4字節vptr)return 0;
}

上述代碼的虛函數表結構如下:

Base類的虛函數表
  • vtable[0] → &Base::func1
  • vtable[1] → &Base::func2
Derived類的虛函數表
  • vtable[0] → &Derived::func1(覆蓋基類的func1)
  • vtable[1] → &Base::func2(繼承基類的func2)
  • vtable[2] → &Derived::func3(新增的虛函數)

注意:

1. 虛函數表是編譯器在編譯期生成的,存儲在只讀數據段(.rodata);

2. 虛表指針是在對象構造時初始化的,指向所屬類的虛函數表;

3. 多態會帶來輕微的性能開銷(多一次指針間接訪問),但通常可以忽略不計。

五、常見問題與面試題

Q1:靜態成員函數可以是虛函數嗎?

A:不可以。因為靜態成員函數屬于類,不屬于某個具體對象,沒有this指針,而虛函數的調用需要通過對象的vptr找到vtable,因此靜態成員函數不能是虛函數。

Q2:構造函數可以是虛函數嗎?

A:不可以。因為對象的vptr是在構造函數執行時初始化的,在構造函數還未執行時,vptr尚未指向正確的虛函數表,因此構造函數不能是虛函數。

Q3:析構函數為什么要設為虛函數?

A:如前文所述,當用基類指針指向派生類對象并刪除時,如果基類析構函數是虛函數,會先調用派生類析構函數,再調用基類析構函數,確保資源正確釋放;否則只會調用基類析構函數,導致派生類資源泄漏。

Q4:多態有什么優缺點?

A:優點:
1. 提高代碼的復用性和可維護性;
2. 提高代碼的擴展性,新增派生類不影響原有代碼;
3. 接口統一,使用者無需關心具體實現。
缺點:
1. 增加了系統復雜度;
2. 帶來輕微的性能開銷(虛函數調用需要查表);
3. 可能隱藏錯誤,調試難度增加。

Q5:什么情況下會發生隱藏(重定義)?

A:派生類中的函數與基類中的函數同名,且不構成重寫時,會發生隱藏:
1. 基類函數不是虛函數,派生類函數與基類函數同名(無論參數是否相同);
2. 基類函數是虛函數,但派生類函數與基類函數參數不同。

Q6:如何判斷一段代碼是否構成多態?

A:同時滿足以下條件:
1. 存在繼承關系;
2. 基類中存在虛函數,派生類重寫了該虛函數;
3. 通過基類的指針或引用調用該虛函數。

六、總結

  • 多態分為編譯時多態(函數重載、模板)和運行時多態(虛函數);
  • 運行時多態的實現條件:基類指針/引用 + 虛函數重寫
  • 虛函數重寫要求:函數名、參數列表、返回值完全相同(協變除外);
  • override關鍵字用于檢查重寫是否正確,final關鍵字用于禁止重寫或繼承;
  • 含有純虛函數的類是抽象類,不能實例化,派生類必須重寫所有純虛函數;
  • 多態的底層是通過虛函數表(vtable)虛表指針(vptr)實現的;
  • 基類析構函數建議設為虛函數,避免派生類對象銷毀時的內存泄漏;

七、結語

今日C++到這里就結束啦,如果覺得文章還不錯的話,可以三連支持一下。感興趣的寶子們歡迎持續訂閱小楓,小楓在這里謝謝寶子們啦~小楓の主頁還有更多生動有趣的文章,歡迎寶子們去點評鴨~C++的學習很陡,時而巨難時而巨簡單,希望寶子們和小楓一起堅持下去~你們的三連就是小楓的動力,感謝支持~

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94651.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94651.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94651.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Visual Scope (Serial_Digital_Scope V2) “串口 + 虛擬示波器” 工具使用記錄

VisualScope 就是一個 “串口 + 虛擬示波器” 的工具,適合在沒有昂貴示波器/邏輯分析儀時做嵌入式調試。它的核心步驟就是 MCU 定時發數據 → PC 串口接收 → 軟件畫波形。 首先準備串口通信工具后,插入電腦,安裝完USB轉串口驅動后,在“我的電腦”-“設備及管理器”-“端口…

c++ 觀察者模式 訂閱發布架構

#include <iostream> #include <vector> #include <algorithm> #include <memory> #include <mutex>// 觀察者接口 class IObserver { public:virtual ~IObserver() default;virtual void update(const std::string& message) 0; };// 主題…

oracle 表空間擴容(增加新的數據文件)

SELECT tablespace_name,file_name,ROUND(bytes / 1024 / 1024, 2) AS size_mb,ROUND(maxbytes / 1024 / 1024, 2) AS max_size_mb,status,autoextensible FROM dba_data_files ORDER BY tablespace_name;--給表空間增加一個新數據庫文件ALTER TABLESPACE EAS_D_EAS_STANDARDAD…

DAY 58 經典時序預測模型2

知識點回顧&#xff1a; 時序建模的流程時序任務經典單變量數據集ARIMA&#xff08;p&#xff0c;d&#xff0c;q&#xff09;模型實戰SARIMA摘要圖的理解處理不平穩的2種差分 n階差分---處理趨勢季節性差分---處理季節性 昨天我們掌握了AR, MA, 和 ARMA 模型&#xff0c;它們…

【人工智能】AI代理重塑游戲世界:動態NPC帶來的革命性沉浸式體驗

還在為高昂的AI開發成本發愁?這本書教你如何在個人電腦上引爆DeepSeek的澎湃算力! 在當今游戲行業迅猛發展的時代,AI代理技術正悄然引發一場革命,尤其是動態非玩家角色(NPC)的應用,將傳統靜態游戲體驗提升至全新的沉浸式境界。本文深入探討AI代理在游戲中的核心作用,從…

服務器關機故障排查:大白話版筆記

注意:本文解釋文字僅供學習交流使用,不構成專業的技術指導或建議;只是理論實例解釋不代表實際運維場景操作,注意鑒別! 運維日常最頭疼的就是服務器 “突然躺平” —— 要么沒操作就自己關機,要么想關還關不掉。 緊急檢查清單 (Cheat Sheet) 服務器突然宕機,重啟后第一…

如何通過docker進行本地部署?

如何通過docker進行本地部署&#xff1f; 在做項目的過程中&#xff0c;想要上線項目的話肯定是不能在我們電腦上進行開發的&#xff0c;要部署到服務器上面&#xff0c;今天就總結一下操作步驟。 1、創建springboot項目 隨便創建一個springboot工程&#xff0c;確保control…

解鎖AI“黑匣”:監督、無監督與強化學習探秘

在當今數字化浪潮洶涌澎湃的時代&#xff0c;AI 決策已然成為推動各領域變革與發展的核心驅動力&#xff0c;從智能語音助手到自動駕駛汽車&#xff0c;從醫療診斷輔助到金融風險預測&#xff0c;AI 決策的身影無處不在&#xff0c;深刻地改變著人們的生活與工作方式。?AI 決策…

F008 vue+flask 音樂推薦評論和可視化系統+帶爬蟲前后端分離系統

文章結尾部分有CSDN官方提供的學長 聯系方式名片 文章結尾部分有CSDN官方提供的學長 聯系方式名片 關注B站&#xff0c;有好處&#xff01; F008 &#x1f3b6;vueflask 音樂推薦和可視化系統帶爬蟲前后端分離系統 編號&#xff1a;F008 B站視頻介紹&#xff1a; vueflask-云音…

海盜王64位dx9客戶端修改篇之二

目前全網&#xff0c;估計也就只有這個是海盜王客戶端3.0的原始版直接升級成64位dx9的了。客戶端非常簡潔&#xff0c;連64位lua都集成進去&#xff0c;除了新更換的64位SDL音樂播放庫dll沒辦法集成外&#xff0c;沒有任何多余的其他文件了。 之前有其他大佬將1.38的改成了dx9的…

點評項目(Redis中間件)第二部分Redis基礎

Redis的java客戶端spring整合了前三種我們只需要學習spring整合的就行了。不過還是有企業使用老一套的原生的jedis。jedis操作引入依賴<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</ve…

LeetCode-19day:貪心算法

貪心算法經典題目總結&#xff08;C實現&#xff09; 貪心算法是一種在每一步選擇中都采取當前狀態下最優&#xff08;即最有利&#xff09;的選擇&#xff0c;從而希望導致結果是全局最優的算法。本文總結了四道經典的貪心算法問題&#xff0c;幫助你更好地理解和掌握貪心算法…

Microsoft Edge WebView2 Runtime:為應用程序提供瀏覽器核心功能

在現代軟件開發中&#xff0c;嵌入網頁內容到應用程序界面是一個常見的需求。Microsoft Edge WebView2 Runtime&#xff08;WebView2運行庫&#xff09;作為微軟操作系統WebView2控件的運行環境&#xff0c;基于Chromium內核構建&#xff0c;為應用程序提供了瀏覽器核心功能&am…

PDF文件中的相鄰頁面合并成一頁,例如將第1頁和第2頁合并,第3頁和第4頁合并

PDF頁面合并工具 這個工具可以將PDF文件中的相鄰頁面合并成一頁&#xff0c;例如將第1頁和第2頁合并&#xff0c;第3頁和第4頁合并&#xff0c;以此類推。 功能 自動檢測PDF文件中的頁面數量將相鄰的頁面合并成一頁處理奇數頁數的PDF文件&#xff08;最后一頁單獨保留&#xff…

git hub初使用問題記錄

問題一、Connection closed by UNKNOWN port 65535設置config文件為Host github.com Hostname ssh.github.com Port 443 User git問題二、ERROR: Repository not found.fatal: Could not read from remote repository.Please make sure you have the correct access rightsand …

解讀 AUTOSAR AP R24-11 Manifest 規范 —— 從部署到安全的全流程支撐

今天我們來拆解 AUTOSAR AP R24-11 版本的《Requirements on Manifest Specification》Manifest 規范要求—— 這份文檔是 Adaptive 平臺軟件 “落地運行” 的核心指南,它解決了一個關鍵問題:如何讓 AP 軟件在車載 ECU 上安全、可靠地部署和通信? 自適應平臺(AP)是啥? 是…

Linux系統 -- 多線程的控制(互斥與同步)

在多線程編程中&#xff0c;多個線程可能同時訪問臨界資源&#xff08;如共享變量、文件、硬件設備等&#xff09;&#xff0c;若缺乏控制會導致數據混亂。互斥和同步是解決該問題的核心機制&#xff0c;其中互斥鎖保證臨界資源的排他訪問&#xff0c;信號量實現線程間的有序協…

一鍵搭建開發環境:制作bash shell腳本

完整腳本&#xff1a; 1.0 #!/bin/bash set -eecho " 開始安裝 AI 開發環境&#xff08;無人交互版&#xff09; "# 檢測是否以 sudo 運行 if [ "$EUID" -eq 0 ]; thenecho "?? 警告&#xff1a;請不要使用 sudo 運行此腳本&#xff01;"echo …

mac m4執行nvm install 14.19.1報錯,安裝低版本node報錯解決

原因 由于node14使用的變異工具鏈太舊&#xff0c;無法適配最新的macOS SDK頭文件導致_studio.h報錯 解決辦法 方法1 更新nvm到最新版本 brew update nvmnvm install 14.19.1 --binary 方法2 啟用Rosetta安裝&#xff08;Intel仿真&#xff09; 1.arch -x86_64 zsh 2.nvm insta…

Codeforces Round 1043 (Div. 3) F. Rada and the Chamomile Valley

F.拉達和甘菊谷 每次測試的時間限制&#xff1a;3 秒 每次測試的內存限制512 兆字節 輸入&#xff1a;標準輸入 輸出&#xff1a;標準輸出 昨天&#xff0c;拉達發現了一個傳送門&#xff0c;可以把她傳送到洋甘菊谷&#xff0c;然后再傳送回來。拉達的快樂無以言表&#xff0c…