[C++]多態詳解

目錄

一、多態的概念

二、靜態的多態

三、動態的多態

3.1多態的定義

3.2虛函數

四、虛函數的重寫(覆蓋)

4.1虛函數

4.2三同

4.3兩種特殊情況

(1)協變

(2)析構函數的重寫

五、C++11中的final和override

5.1-C++98防止一個類被繼承的方法

5.2-C++11final關鍵字

5.3-C++11override關鍵字

六、重載、覆蓋(重寫)、隱藏(重定義)的對比

七、抽象類(接口類)

7.1概念

7.2接口繼承和實現繼承

八、多態的實現原理

8.1虛函數表

8.2虛函數表的生成

8.3多態的原理

8.4動態綁定與靜態綁定

九、單繼承和多繼承關系的虛函數表

9.1單繼承中的虛函數表

9.2多繼承中的虛函數表

十、問答題

1. 什么是多態?

2. 什么是重載、重寫(覆蓋)、重定義(隱藏)?

3、多態的實現原理?

4、inline可以是虛函數嗎?

5、靜態成員可以是虛函數嗎?

6、構造函數可以是虛函數嗎?

7、析構函數可以是虛函數嗎?

8、對象調用普通成員函數快還是虛函數快?

9.、虛函數表是在什么階段生成的,存在哪的?

10、C++菱形繼承的問題?虛繼承的原理??

11、什么是抽象類?抽象類的作用??


一、多態的概念

?多態指多種形態。不同的對象完成同一件事情,但是結果不同。例如公交刷卡行為:成人刷卡全價,學生刷卡半價。亦或是不同的客戶來消費,金卡會員8折,銀卡會員9折,普通會員無折扣。


二、靜態的多態

靜態的多態是在編譯時產生不同。例如函數重載就是一種靜態的多態行為。看上去是在調用同一個函數,但是會產生不同的行為。

int main()
{int a=1;double b=2.3;std::cout<<a<<std::endl;std::cout<<b<<std::endl;return 0;
}

三、動態的多態

3.1多態的定義

????????動態的多態是在運行時產生不同。

????????構成多態的條件:缺一不可,否則就不構成多態。

1. 必須通過基類的指針或者引用調用虛函數

2. 被調用的函數必須是虛函數,且派生類必須對基類的虛函數進行重寫

3.2虛函數

虛函數:即被virtual修飾的類成員函數稱為虛函數。

class Person 
{
public:virtual void BuyTicket() { cout << "買票-全價" << endl;}
};
class Student : public Person
{
public:
virtual void BuyTicket(){cout<<"買票-半價"<<endl;}
};

注意虛函數和虛繼承雖然都使用了virtual關鍵字,但是它們沒有關系。


四、虛函數的重寫(覆蓋)

總結構成重寫的條件:虛函數 + 三同 + 兩種特殊情況

4.1虛函數

子類重寫父類虛函數時,子類“三同”函數不寫virtual也構成重寫,但是不規范。C++設計者的初衷是父類寫了virtual,即使子類不寫,也構成多態,那就不會出現內存泄漏的情況了。

父類的 virtual 一定不能省略 – 虛函數的繼承是接口繼承,也就是說,子類中繼承得到的虛函數和父類虛函數的函數接口是完全相同的,而子類如果對虛函數進行重寫,重寫的也只是虛函數的實現,并沒有改變虛函數的接口,所以即使我們不加 virtual 子類虛函數的類型也和父類一樣,是虛函數類型。為了程序的可讀性,我們建議子類虛函數也加上 virtual

我們在繼承關系中,建議子類虛函數加上 virtual,而可以無腦地將父類析構定義為虛函數(理由下面會講解)

4.2三同

返回值類型函數名稱參數列表均相同。

4.3兩種特殊情況

(1)協變

構成重寫需要成員函數返回值相同,但是存在例外,當返回值是構成父子關系的指針或引用時,它們也構成重寫。但是父類返回值一定要用父指針/父引用,子必須用子指針/子引用,不能顛倒。

class A{};class B : public A {};class Person {public:virtual A* f() {return new A;}};class Student : public Person {public:virtual B* f() {return new B;}};

(2)析構函數的重寫

基類與派生類析構函數的名字不同,其實不然,這里可以理解為編譯器對析構函數的名稱做了特殊處 理,編譯后析構函數的名稱統一處理成destructor

如果基類的析構函數為虛函數,此時派生類析構函數只要定義,無論是否加virtual關鍵字, 都與基類的析構函數構成重寫,雖然基類與派生類析構函數名字不同。

class Person {public:virtual ~Person() {cout << "~Person()" << endl;}};class Student : public Person {public:virtual ~Student() { cout << "~Student()" << endl; }};只有派生類Student的析構函數重寫了Person的析構函數,下面的delete對象調用析構函
數,才能構成多態,才能保證p1和p2指向的對象正確的調用析構函數。
int main(){Person* p1 = new Person;Person* p2 = new Student;delete p1;delete p2;}return 0;

父子構造函數構成多態,那就不看p1p2的類型了,p1p2指向哪個對象,就調用哪個對象的析構函數。


五、C++11中的final和override

從上面可以看出,C++對函數重寫的要求比較嚴格,但是有些情況下由于疏忽,可能會導致函數 名字母次序寫反而無法構成重載,而這種錯誤在編譯期間是不會報出的,只有在程序運行時沒有 得到預期結果才來debug會得不償失,因此:C++11提供了override和final兩個關鍵字,可以幫 助用戶檢測是否重寫。

5.1-C++98防止一個類被繼承的方法

class Person
{
public:static Person CreateObj(){//new Person;return Person();}
private:Person(){}
};
class Student : public Person
{
public: 
};
int main()
{Person p=Person::CreateObj();return 0;
}

C++98通過把構造函數變為私有的方式,讓子類繼承后根本構造不出父類對象。

但是父類卻可以通過靜態的“偷家”函數構造對象。

5.2-C++11final關鍵字

(1)final修飾類,防止該類被繼承

class Person final
{
public:
};

(2)final:修飾虛函數,表示該虛函數不能再被重寫

class Car{public:virtual void Drive() final {}};class Benz :public Car{public:virtual void Drive() {cout << "Benz-舒適" << endl;}};

5.3-C++11override關鍵字

檢查派生類虛函數是否重寫了基類某個虛函數,如果沒有重寫編譯報錯

class Car{public:virtual void Drive(){}};class Benz :public Car {public:virtual void Drive() override {cout << "Benz-舒適" << endl;}};

六、重載、覆蓋(重寫)、隱藏(重定義)的對比


七、抽象類(接口類)

7.1概念

在虛函數的后面寫上 =0 ,則這個函數為純虛函數。包含純虛函數的類叫做抽象類(也叫接口 類),抽象類不能實例化出對象。派生類繼承后也不能實例化出對象。

只有重寫純虛函數,派生 類才能實例化出對象。純虛函數規范了派生類必須重寫,另外純虛函數更體現出了接口繼承。

class Car{public:virtual void Drive() = 0;};class Benz :public Car{public:virtual void Drive(){cout << "Benz-舒適" << endl;}};class BMW :public Car{public:virtual void Drive(){cout << "BMW-操控" << endl;}};void Test(){Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();}

抽象類的作用是強制子類進行重寫。

7.2接口繼承和實現繼承

普通函數繼承是一種實現繼承,派生類繼承了基類函數,可以使用函數,繼承的是函數的實現。

虛函數的繼承是一種接口繼承,派生類繼承的是基類虛函數的接口,目的是為了重寫,達成 多態,繼承的是接口。接口繼承會繼承父類的類作用限定符和缺省參數。

所以如果不實現多態,不要把函數定義成虛函數。


八、多態的實現原理

8.1虛函數表

這里常考一道筆試題:sizeof(Base)是多少?
class Base{public:virtual void Func1(){cout << "Func1()" << endl;}private:int _b = 1;};

通過觀察測試我們發現b對象是8bytes,除了_b成員,還多一個__vfptr放在對象的前面(注意有些 平臺可能會放到對象的最后面,這個跟平臺有關),對象中的這個指針我們叫做虛函數表指針(v代 表virtual,f代表function)。

一個含有虛函數的類中都至少都有一個虛函數表指針,因為虛函數 的地址要被放到虛函數表中,虛函數表也簡稱虛表。

8.2虛函數表的生成

針對上面的代碼我們做出以下改造
1、我們增加一個派生類Derive去繼承Base
2、Derive中重寫Func1
3、Base再增加一個虛函數Func2和一個普通函數Func3class 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 Derive : public Base{public:virtual void Func1(){cout << "Derive::Func1()" << endl;}private:int _d = 2;};int main(){Base b;Derive d;cout << "Derive::Func1()" << endl;return 0;}

通過觀察和測試,我們發現了以下幾點問題:

1. 派生類對象d中也有一個虛表指針,d對象由兩部分構成,一部分是父類繼承下來的成員,虛 表指針也就是存在部分的另一部分是自己的成員。

2. 基類b對象和派生類d對象虛表是不一樣的,這里我們發現Func1完成了重寫,所以d的虛表 中存的是重寫的Derive::Func1,所以虛函數的重寫也叫作覆蓋,覆蓋就是指虛表中虛函數 的覆蓋。重寫是語法的叫法,覆蓋是原理層的叫法

3. 另外Func2繼承下來后是虛函數,所以放進了虛表,Func3也繼承下來了,但是不是虛函 數,所以不會放進虛表。

4. 虛函數表本質是一個存虛函數指針的指針數組,一般情況這個數組最后面放了一個nullptr

5. 總結一下派生類的虛表生成

a.先將基類中的虛表內容拷貝一份到派生類虛表中

b.如果派生 類重寫了基類中某個虛函數,用派生類自己的虛函數覆蓋虛表中基類的虛函數

c.派生類自己 新增加的虛函數按其在派生類中的聲明次序增加到派生類虛表的最后。

6. 這里還有一個童鞋們很容易混淆的問題:虛函數存在哪的?虛表存在哪的? 答:

注意 虛表存的是虛函數指針,不是虛函數,虛函數和普通函數一樣的,都是存在代碼段的,只是 他的指針又存到了虛表中。另外對象中存的不是虛表,存的是虛表指針。那么虛表存在哪的 呢?實際我們去驗證一下會發現vs下是存在代碼段的。

8.3多態的原理

 class Person {public:virtual void BuyTicket() { cout << "買票-全價" << endl; }};class Student : public Person {public:virtual void BuyTicket() { cout << "買票-半價" << endl; }};void Func(Person& p){p.BuyTicket();}int main(){Person Mike;Func(Mike);Student Johnson;Func(Johnson);return 0;}

?1. 觀察下圖的紅色箭頭我們看到,p是指向mike對象時,p->BuyTicket在mike的虛表中找到虛 函數是Person::BuyTicket。

2. 觀察下圖的藍色箭頭我們看到,p是指向johnson對象時,p->BuyTicket在johson的虛表中 找到虛函數是Student::BuyTicket。

3. 這樣就實現出了不同對象去完成同一行為時,展現出不同的形態。

4. 反過來思考我們要達到多態,有兩個條件,一個是虛函數覆蓋,一個是對象的指針或引用調 用虛函數。反思一下為什么?

5. 滿足多態以后的函數調用,不是在編譯時確定的,是運行 起來以后到對象的中取找的。不滿足多態的函數調用時編譯時確認好的。

8.4動態綁定與靜態綁定

?1. 靜態綁定又稱為前期綁定(早綁定),在程序編譯期間確定了程序的行為,也稱為靜態多態, 比如:函數重載

2. 動態綁定又稱后期綁定(晚綁定),是在程序運行期間,根據具體拿到的類型確定程序的具體 行為,調用具體的函數,也稱為動態多態。


九、單繼承和多繼承關系的虛函數表

9.1單繼承中的虛函數表

class Base { 
public :virtual void func1() { cout<<"Base::func1" <<endl;}virtual void func2() {cout<<"Base::func2" <<endl;}private :int a;};class Derive :public Base { 
public :virtual void func1() {cout<<"Derive::func1" <<endl;}virtual void func3() {cout<<"Derive::func3" <<endl;}virtual void func4() {cout<<"Derive::func4" <<endl;}private :int b;};

9.2多繼承中的虛函數表

class Base1 {public:virtual void func1() {cout << "Base1::func1" << endl;}virtual void func2() {cout << "Base1::func2" << endl;}private:int b1;};class Base2 {public:virtual void func1() {cout << "Base2::func1" << endl;}virtual void func2() {cout << "Base2::func2" << endl;}private:int b2;};class Derive : public Base1, public Base2 {public:virtual void func1() {cout << "Derive::func1" << endl;}virtual void func3() {cout << "Derive::func3" << endl;}private:int d1;};

上圖可以看出:多繼承派生類的未重寫的虛函數放在第一個繼承基類部分的虛函數表中


十、問答題

1. 什么是多態?

多態指多種形態。不同的對象完成同一件事情,但是結果不同。例如公交刷卡行為:成人刷卡全價,學生刷卡半價。亦或是不同的客戶來消費,金卡會員8折,銀卡會員9折,普通會員無折扣。

2. 什么是重載、重寫(覆蓋)、重定義(隱藏)?

函數重載:(1)兩個函數在同一作用域

? ? ? ? ? ? ? ? ? (2)函數名相同,參數列表不同,返回值沒有要求;

重寫: (1)兩個函數必須位于子類和父類中

? ? ? ? ? ?(2)函數名、參數列表、返回值必須相同(協變除外)

? ? ? ? ? ?(3)兩個函數均為虛函數;

隱藏:(1)兩個函數必須位于子類和父類中

? ? ? ? ? ?(2)函數名相同

? ? ? ? ? ?(3)不構成重寫,就構成隱藏

3、多態的實現原理?

對于多態的實現原理,必須先從構成多態的條件說起:

1、必須通過父類對象的引用或指針當做形參調用虛函數。

2、子類必須完成對父類虛函數的重寫且被調用的函數是虛函數。

? ? ? ? 子類和父類的虛函數表指針、虛函數表、重寫的虛函數的地址均不相同,我們傳入一個父類對象,它使用的是源自父類的虛函數,傳入一個從子類切片而來的父類對象,這個對象中的虛函數是子類重寫的虛函數。雖說這兩個都是父類對象,但是對象體內的虛函數并不是同一個,所以會產生不同的行為,這便是多態的原理。

4、inline可以是虛函數嗎?

?inline可以是虛函數。調用時,如果不構成多態,這個函數就保持inline屬性。如果構成多態,就不具備inline屬性,因為多態是要在運行時去對象的虛函數表里面找虛函數,所以在編譯時,不能使用inline進行展開。

5、靜態成員可以是虛函數嗎?

靜態成員不能是虛函數。因為靜態成員沒有this指針,在外部可以直接使用類名::成員函數的方式對靜態成員函數進行調用,但是調用虛函數需要通過對象才能找到虛函數表,所以靜態成員不能是虛函數。

6、構造函數可以是虛函數嗎?

構造函數不能是虛函數。因為對象的虛函數表指針是在構造函數的初始化列表中進行初始化。(先有雞還是先有蛋的問題)

7、析構函數可以是虛函數嗎?

構函數可以是虛函數,用于處理子類對象交給父類的指針管理的情況。

8、對象調用普通成員函數快還是虛函數快?

如果不構成多態,即使是虛函數,也是在編譯階段確定調用地址,速度一樣快;但是一旦構成多態,編譯器在運行時通過對象去虛函數表中確定虛函數的調用地址,這個時候就是普通函數快了。

9.、虛函數表是在什么階段生成的,存在哪的?

?虛函數表是在編譯階段就生成的,一般情況 下存在代碼段(常量區)的。

10、C++菱形繼承的問題?虛繼承的原理??

注意這里不要把虛函數表和虛基表搞混了。

菱形繼承有數據冗余和二義性的問題。

通過虛基表指針找到虛基表,虛基表中存的數據偏移量。再通過偏移量可以找到有冗余和二義性的數據。

11、什么是抽象類?抽象類的作用??

抽象類又稱接口類。包含純虛函數的類被稱為抽象類,在虛函數后邊加個=0,這個虛函數就被叫做純虛函數。抽象類不能實例化出對象。在現實世界中沒有對應的實物,就可以定義為抽象類。例如職能類、Person類等。

?抽象類強制重寫了虛函數,另外體現接口繼承的關系。子類繼承抽象類后,也變成了抽象類。這就強制用戶對純虛函數進行重寫,對虛函數的重寫是一種接口繼承,子類會繼承虛函數的函數名及缺省值,但不會繼承實現。

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

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

相關文章

WEB安全--SQL注入--PDO與繞過

一、PDO介紹&#xff1a; 1.1、原理&#xff1a; PDO支持使用預處理語句&#xff08;Prepared Statements&#xff09;&#xff0c;這可以有效防止SQL注入攻擊。預處理語句將SQL語句與數據分開處理&#xff0c;使得用戶輸入的數據始終作為參數傳遞給數據庫&#xff0c;而不會直…

ES12 weakRefs的用法和使用場景

ES12 (ECMAScript 2021) 特性總結&#xff1a;WeakRef 1. WeakRef 概述 描述 WeakRef 是 ES12 引入的一個新特性&#xff0c;用于創建對對象的弱引用。弱引用不會阻止垃圾回收器回收對象&#xff0c;即使該對象仍然被弱引用持有。WeakRef 通常與 FinalizationRegistry 結合使…

50頁精品PPT | 某大數據資產平臺建設項目啟動會材料

該PPT主要介紹了某集團大數據資產平臺建設項目的啟動會材料&#xff0c;圍繞數據作為數字經濟時代核心生產要素的背景&#xff0c;結合國家戰略和集團數字化轉型需求&#xff0c;分析了當前數據資源整合不足、孤島現象嚴重、質量管控薄弱及共享機制不完善等問題&#xff0c;提出…

8.【線性代數】——求解Ax=b

八 求解Axb 1. 解Axb求特解 x p x_p xp?求特解 x n x_n xn?所有解 2. Axb什么時候有解3. A m ? n A_{m * n} Am?n?不同秩的Axb解分析3.1 列滿秩 rn<m3.2 行滿秩 rm<n3.3 rmn3.4 r<m 且 r < n3.5 綜述 1. 解Axb 求解 { x 1 2 x 2 2 x 3 2 x 4 b 1 2 x 1…

動靜態鏈接與加載

目錄 靜態鏈接 ELF加載與進程地址空間&#xff08;靜態鏈接&#xff09; 動態鏈接與動態庫加載 GOT表 靜態鏈接 對于多個.o文件在沒有鏈接之前互相是不知到對方存在的&#xff0c;也就是說這個.o文件中調用函數的的跳轉地址都會被設定為0&#xff08;當然這個函數是在其他.…

Web 后端 請求與響應

一 請求響應 1. 請求&#xff08;Request&#xff09; 客戶端向服務器發送的HTTP請求&#xff0c;通常包含以下內容&#xff1a; 請求行&#xff1a;HTTP方法&#xff08;GET/POST等&#xff09;、請求的URL、協議版本。 請求頭&#xff08;Headers&#xff09;&#xff1a;…

【Excel筆記_6】條件格式和自定義格式設置表中數值超過100保留1位,超過1000保留0位,低于100為默認

方法一&#xff1a;自定義格式 選中需要設置格式的單元格區域。右鍵選擇設置單元格格式&#xff0c;或者在工具欄中選擇開始 -> 數字 -> 自定義格式。在類型框中輸入以下自定義格式&#xff1a; [>1000]0;[>100]0.0;G/通用格式解釋&#xff1a; [>1000]0&…

排序與算法:希爾排序

執行效果 希爾排序的執行效果是這樣的&#xff1a; 呃……看不懂嗎&#xff1f;沒關系&#xff0c;接著往下看介紹 算法介紹 希爾排序算法&#xff08;Shell Sort&#xff09;是按其設計者希爾&#xff08;Donald Shell&#xff09;的名字命名&#xff0c;該算法由 1959 年公布…

Python HTTP 請求工具類 HttpUtils:簡化 HTTP 請求的高效工具

在現代的 Web 開發和 API 集成中,HTTP 請求是最常見的操作之一。無論是獲取數據、提交表單,還是與 RESTful API 交互,我們都需要頻繁地發送 HTTP 請求。為了簡化這些操作,提升代碼的可讀性和可維護性,我們可以使用一個高效的工具類——HttpUtils。本文將詳細介紹 HttpUtil…

親測Windows部署Ollama+WebUI可視化

一. Ollama下載 登錄Ollama官網(Ollama)點擊Download進行下載 如果下載很慢可用以下地址下載&#xff1a; https://github.com/ollama/ollama/releases/download/v0.5.7/OllamaSetup.exe 在DeepSeek官網上&#xff0c;你可以直接點擊【model】 到達這個界面之后&#xff0c;…

用xml配置spring, bean標簽有哪些屬性?

用xml配置spring, bean標簽有哪些屬性? 在Spring框架中&#xff0c;使用XML配置文件時&#xff0c;<bean>標簽用于定義一個Bean。以下是一些常用的<bean>標簽屬性&#xff1a; 1. class 描述&#xff1a;指定Bean的類名。示例&#xff1a;<bean id"myBe…

50頁PDF|數字化轉型成熟度模型與評估(附下載)

一、前言 這份報告依據GBT 43439-2023標準&#xff0c;詳細介紹了數字化轉型的成熟度模型和評估方法。報告將成熟度分為五個等級&#xff0c;從一級的基礎轉型意識&#xff0c;到五級的基于數據的生態價值構建與創新&#xff0c;涵蓋了組織、技術、數據、資源、數字化運營等多…

golang panic信息捕獲

背景 我們的日志接入阿里云sls平臺&#xff0c;但是&#xff0c;日志是以json的格式存儲在阿里云sls平臺上&#xff0c;程序中產生的error,info等日志都可以實現以json的格式打印。但是&#xff0c;golang程序中產生的panic信息本身不是以json的格式輸出&#xff0c;這就導致p…

攔截器VS過濾器:Spring Boot中請求處理的藝術!

目錄 一、攔截器&#xff08;Interceptor&#xff09;和過濾器&#xff08;Filter&#xff09;&#xff1a;都是“守門員”&#xff01;二、如何實現攔截器和過濾器&#xff1f;三、攔截器和過濾器的區別四、執行順序五、真實的應用場景六、總結 &#x1f31f;如果喜歡作者的講…

FastGPT及大模型API(Docker)私有化部署指南

??歡迎關注【AI技術開發者】 ? 經過優化&#xff0c;在不影響FastGPT功能的情況下&#xff0c;大幅降低了部署的設備配置要求&#xff0c;僅需1c1h即可正常部署使用。 官方要求配置&#xff1a; ? ? 優化后的實際占用情況&#xff1a; 運行內存僅需370M&#xff08…

解決 WSL Ubuntu 中 /etc/resolv.conf 自動重置問題

解決 WSL Ubuntu 中 /etc/resolv.conf 自動重置問題 前言問題描述問題原因嘗試過的命令及分析解決方案&#xff1a;修改 wsl.conf 禁用自動生成總結 前言 在使用 Windows Subsystem for Linux (WSL) 的 Ubuntu 子系統時&#xff0c;你可能會遇到 /etc/resolv.conf 文件被自動重…

【第15章:量子深度學習與未來趨勢—15.3 量子深度學習在圖像處理、自然語言處理等領域的應用潛力分析】

一、開篇:為什么我們需要關注這場"量子+AI"的世紀聯姻? 各位技術愛好者們,今天我們要聊的這個話題,可能是未來十年最值得押注的技術革命——量子深度學習。這不是簡單的"1+1=2"的物理疊加,而是一場可能徹底改寫AI發展軌跡的范式轉移。 想象這樣一個…

企業軟件合規性管理:構建高效、安全的軟件資產生態

引言 在數字化轉型的浪潮下&#xff0c;企業的軟件使用方式日益多元化&#xff0c;涉及云端、訂閱制、永久授權及浮動許可等多種模式。然而&#xff0c;隨著軟件資產的增多&#xff0c;企業面臨著合規性管理的嚴峻挑戰&#xff1a;非法軟件使用、許可證管理不當、軟件資產閑置…

python學習筆記,python處理 Excel、Word、PPT 以及郵件自動化辦公

文章目錄 前言一、環境搭建1. 下載 Python2. 安裝 Python 二、處理 Excel 文件&#xff08;openpyxl庫&#xff09;三、 處理 Word 文件&#xff08;python-docx庫&#xff09;四、 處理 PPT 文件&#xff08;python-pptx庫&#xff09;五、 自動發送郵件&#xff08;smtplib和…

Python 基礎-循環

目錄 簡介 break continue 小結 簡介 要計算123&#xff0c;我們可以直接寫表達式&#xff1a; >>> 1 2 3 6要計算123...10&#xff0c;勉強也能寫出來。 但是&#xff0c;要計算123...10000&#xff0c;直接寫表達式就不可能了。 為了讓計算機能計算成千上…