-
面向過程
1.1 面向過程特點
1.2 通俗解釋:煮方便面
1.3 面向過程實現代碼
1.4 特點總結 -
面向對象
2.1 面向對象特點
2.2 通俗解釋:對象協作思維
2.3 面向對象實現代碼
2.4 特點總結 -
面向對象和面向過程總結
-
C++ 面向對象介紹
4.1 面向對象三大基本特征-
封裝(Encapsulation)
-
繼承(Inheritance)
-
多態(Polymorphism)
4.2 三大特征的通俗解釋
-
-
C++ 類與對象初識
5.1 類的定義
5.2 類的對象
5.3 類的訪問控制與封裝
5.4 類的成員函數-
聲明與實現都放在 .h 文件中
-
聲明放在 .h 文件,定義放在 .cpp 文件
-
-
總結
面向過程和面向對象
面向過程
核心是強調過程/步驟,程序就是一系列函數和語句的組合,把問題分解為一系列步驟(函數),數據在函數間傳遞
面向過程特點:
- 以函數為中心: 函數是主要的組織單位
- 數據與函數分離:數據結構獨立存在,函數對數據進行操作
- 自頂向下設計:先規劃整體流程,再逐步細化
- 適合小型程序:邏輯簡單,編寫快速
面向對象
強調對象,程序由對象組成,對象封裝了數據(屬性)和行為(方法),面向對象是通過模擬現實世界中的事物和關系來解決問題
面向對象特點:
- 以對象為中心: 對象是基本單位
- 數據與方法封裝:對象內部隱藏實現細節,通過接口與外部交互
- 三大特性:封裝(Encapsulation)、繼承(Inheritance)、多態(Polymorphism
- 適合大型復雜系統:可擴展,可復用,可維護
通俗解釋
以煮方便面為例對比面向過程和面向對象
面向過程:
思維方式: 一步步按流程來做
- 燒開水
- 打開調料包倒進碗里
- 把面餅放進開水煮熟
- 把面和湯放進碗里
- 等待一下,就可以吃了
這里每個動作就是一個"函數/步驟",整個煮面過程就是把這些步驟順序執行
面向過程實現代碼:
#include <iostream>
#include <thread>
#include <chrono> // 用于等待
using namespace std;
// 步驟 1: 燒開水
void boilWater() {cout << "正在燒開水..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "水已經燒開了。" << endl;
}
// 步驟 2: 打開調料包倒進碗里
void addSeasoning() {cout << "打開調料包,倒進碗里。" << endl;
}
// 步驟 3: 把面餅放進開水煮熟
void cookNoodles() {cout << "把面餅放進開水里煮..." << endl;this_thread::sleep_for(chrono::seconds(2));cout << "面已經煮熟了。" << endl;
}
// 步驟 4: 把面和湯放進碗里
void serveNoodles() {cout << "把面和湯一起倒進碗里。" << endl;
}
// 步驟 5: 等待一下,就可以吃了
void waitAndEat() {cout << "等待冷卻一下..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "可以開動啦!" << endl;
}
int main() {boilWater();addSeasoning();cookNoodles();serveNoodles();waitAndEat();return 0;
}
特點:
- 以"過程為主"
- 如果要換成"煮餃子",要重新寫一套步驟
- 不強調"面"本身的特性,只關心動作順序
面向對象:
思維方式:把事物抽象成對象 - 有一個水壺對象,它有屬性: 容量,水溫,有方法: 燒水()
- 有一個面對象,它有屬性:面餅大小,口味,有方法: 煮()
- 有一個調料對象,它有方法: 添加()
- 有一個人對象,他只需要調用
person.做飯(面, 水壺, 調料)
只要調用對象的方法,就能完成煮面
這里強調的是對象之間的協作,而不是具體的步驟細節
面向對象實現代碼:
#include <iostream>
#include <thread>
#include <chrono>using namespace std;// 水壺對象
class Kettle {
public:void boilWater() {cout << "水壺開始燒水..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "水壺燒開了水。" << endl;}
};// 調料對象
class Seasoning {
public:void addToBowl() {cout << "調料包已倒入碗中。" << endl;}
};// 面對象
class Noodle {
public:void cook() {cout << "面餅放進開水中煮..." << endl;this_thread::sleep_for(chrono::seconds(2));cout << "面已經煮熟了。" << endl;}
};// 人對象
class Person {
public:void cookNoodles(Kettle& kettle, Seasoning& seasoning, Noodle& noodle) {kettle.boilWater(); // 調用水壺的方法seasoning.addToBowl(); // 調用調料的方法noodle.cook(); // 調用面的煮方法cout << "把面和湯一起倒進碗里。" << endl;cout << "等待冷卻一下..." << endl;this_thread::sleep_for(chrono::seconds(1));cout << "可以開動啦!" << endl;}
};int main() {Kettle kettle;Seasoning seasoning;Noodle noodle;Person person;person.cookNoodles(kettle, seasoning, noodle);return 0;
}
特點:
- 以"對象"為主
- 如果換成"煮餃子",只需要定義一個餃子對象,人對象調用==做飯(餃子,水壺,調料)==就行
- 強調復用性和擴展性
面向對象和面向過程總結
面向過程是一種以步驟和函數為核心的編程思想,強調“怎么做”,適合小型、邏輯清晰的程序;而面向對象則以對象及其屬性和行為為核心,強調“誰來做”,通過封裝、繼承和多態實現更好的復用與擴展,適合構建大型、復雜、可維護的系統
c++面向對象介紹
C++ 面向對象(OOP, Object-Oriented Programming)是一種程序設計思想,它將現實世界中的事物抽象成“對象”,通過對象之間的交互來完成程序功能。C++ 在 C 的基礎上引入了類(class)和對象(object),使得它既支持面向過程(POP),又支持面向對象。
面向對象三大基本特征
C++ 面向對象的核心特性是 封裝、繼承、多態:
- 封裝
- 把數據(成員變量)和操作數據的函數(成員函數)封裝到類中,形成一個整體。
- 提供
public / private / protected
訪問權限,保證數據安全。 - 舉例:銀行卡類,
余額
是私有的,必須通過取錢()
、存錢()
方法來訪問。
- 繼承
- 一個類可以繼承另一個類的成員(變量和方法)。
- 允許代碼復用,同時可以擴展功能
- 舉例:
學生類
繼承人類
,就自動擁有了姓名、年齡屬性,還可以擴展為學號、成績。
- 多態
- 相同的操作針對不同對象有不同的表現。
- 分為 靜態多態(函數重載、運算符重載)和 動態多態(虛函數 + 基類指針/引用)。
- 舉例:
動物
類有一個speak()
方法,狗
調用時輸出“汪汪”,貓
調用時輸出“喵喵”。
面向對象三大基本特征的通俗解釋
封裝就像一個自動售貨機,你只需要按按鈕投幣(調用接口),不需要知道機器內部怎么找零,怎么調貨(內部實現被隱藏),在編程里,封裝就是把數據和操作打包起來,只暴露需要的部分。可以保護數據安全,別人不能亂動
繼承就像兒子繼承父親的基因和財產,兒子天生就有父親的特征(屬性和方法,但兒子還可以有自己獨特的技能(擴展功能)。在編程里,繼承就是子類自動擁有父類的代碼,可以復用和擴展。可以不用重復造輪子
多態就像大家就像大家都能說“打招呼”,但表達方式不同:
- 中國人說:“你好!”
- 美國人說:“Hello!”
- 日本人說:“こんにちは!”
雖然動作一樣,但不同人表現不同,在編程里,多態就是同一個接口,不同對象有不同的實現。可以讓代碼更靈活
C++類與對象初識
- 類(class):定義了一類事物的屬性和行為,是一種模板/藍圖
- 對象(object):類的實例,是實際存在的個體
類的定義
類的定義由關鍵字class
開始,并通過{}
包裹類的內容,類的成員包括:
- 數據成員:用于存儲類對象的狀態(屬性)
- 成員函數:描述對象可以執行的行為(操作)
class Car {
private:string model; // 數據成員int year; // 數據成員
public:// 成員函數:用來設置車輛的型號void setModel(string m);// 成員函數:用來獲取車輛的型號string getModel();// 成員函數:用來設置車輛的年份void setYear(int y);// 成員函數:用來獲取車輛的年份int getYear();
};
類的對象
類定義之后,我們可以創建該類的對象,類的對象即是類的實例化
int main() {Car myCar; // 創建一個名為 myCar 的 Car 類型對象myCar.setModel("BMW"); // 設置 myCar 的 modelmyCar.setYear(2021); // 設置 myCar 的 yearcout << myCar.getModel() << " " << myCar.getYear() << endl; // 輸出:BMW 2021return 0;
}
類的訪問控制與封裝
想象一下你在銀行開了一個賬戶,賬戶里有余額,你或者其他人都不能跑到銀行的數據庫去修改余額,比如改成999999999999
,這樣做明顯是不合理的,銀行只給你兩個合法的窗口:存錢和取錢,這樣設計的好處有:你的余額不會被隨便修改,安全性高,你只需要關心“怎么存取錢”,而不用操心銀行內部如何記賬,銀行后臺可以隨時升級換系統,對客戶來說使用方式不變,這其實就是封裝與訪問控制的真實寫照
為了保護數據安全,簡化使用,方便維護,體現面向對象思想,C++要對類進行訪問控制與封裝。
在C++中,類的成員默認是私有的,也就是說,外部無法直接訪問類的成員變量,如果希望外部能夠訪問成員,必須通過公共接口來提供訪問權限
訪問權限:
- public:公有成員,類外部可以訪問
- private:私有成員,類外部無法直接訪問
- protected:保護成員,類外部無法直接訪問,但可以被派生類訪問
class Car {
private:string model; // 私有成員變量
public:void setModel(string m) { model = m; } // 公有成員函數string getModel() { return model; } // 公有成員函數
};
類的成員函數
類成員函數的定義方式
在C++中,類中的成員函數可以通過兩種方式進行定義:
-
將類的聲明與實現都放在一個
.h
文件中 -
將類的聲明放在
.h
文件中,將實現放在.cpp
文件中
我們首先來看第一種方式:
將聲明和定義都放在 .h
文件中的方式
這種做法并不推薦,主要有以下幾個問題:
-
可能導致重復定義:如果
.h
文件被多個源文件包含,就會在每個源文件中生成一份函數的實現,導致鏈接時發生重復定義錯誤。 -
編譯速度變慢:每個源文件都會重新編譯類的實現部分,導致編譯時間增加。
-
模塊邊界不清晰:將實現放在頭文件中,會讓代碼的結構變得不清晰,維護起來比較困難。
例如,下面是一個簡單的例子:
#pragma once
#include <iostream>
#include <string>class Person {std::string _name;std::string _sex;int _age;
public:Person(std::string name, std::string sex, int age) {_name = name;_sex = sex;_age = age;}void show(); // 函數聲明
};// 這里是函數定義,直接放在了頭文件中
void Person::show() {std::cout << "姓名:" << _name << std::endl;std::cout << "性別:" << _sex << std::endl;std::cout << "年齡:" << _age << std::endl;
}
#include"Person.h"
int main()
{Person p("張三", "男", 20);p.show();
}
然后在另一個 .cpp
文件中:
#include"Person.h"
void test()
{Person p1("張三", "男", 20);p1.show();
}
上述代碼不能成功編譯,原因是頭文件中的函數定義會在每個包含該頭文件的 .cpp
文件中生成一份,最終會導致鏈接時出現重復定義的錯誤。
即使沒有發生重復定義,編譯速度也會因為每個源文件都需要重新編譯函數實現部分而變慢。此外,這種做法會導致模塊之間的邊界不清晰,代碼的結構會變得不容易維護。
將類的聲明放在 .h
文件中,將實現放在 .cpp
文件中
將類的聲明放在.h文件中,實現放在.cpp
文件中,是C++開發中的標準做法,不僅解決了上面重復定義的問題還帶來了提升編譯效率,增強代碼的模塊化、封裝性 和 可維護性,同時也提高了 代碼的可讀性 和 可重用性 的好處。這種做法是C++中的標準實踐
總結
在本篇博客中,我們對比了面向過程(Procedural Programming)與面向對象(Object-Oriented Programming)兩種常見的編程思想,并通過通俗易懂的示例進行了講解。
-
面向過程強調程序的執行順序,適用于邏輯簡單、功能明確的小型程序。它通過將問題拆解為一系列步驟或函數,著重于“怎么做”。
-
面向對象則通過模擬現實世界中的對象與關系,將數據與操作封裝到對象中,強調“誰來做”。它通過封裝、繼承和多態這三大特性,提升了代碼的復用性、擴展性和可維護性,適合大型、復雜的系統設計。
通過代碼示例,我們展示了兩種思想在實際編程中的應用。面向過程的設計直接關注操作步驟,靈活快捷,但擴展性差;而面向對象則通過抽象和封裝將數據與行為結合,便于擴展與維護。不同的場景下,我們可以根據程序的復雜度和需求來選擇合適的設計思想。
在學習和使用面向對象時,我們還討論了類與對象的基本概念、封裝與訪問控制的實現方式,了解了如何設計和組織代碼,使其更具可讀性、可維護性與可擴展性。
最終,面向過程和面向對象并不是對立的,二者各有優劣。在實際開發中,我們往往會根據具體需求綜合使用它們,從而達到最佳的開發效果。掌握這兩種編程思想,并在合適的場景中應用,將使我們成為更高效、更有創造力的軟件開發者。