3348 字
17 分鐘
🎓【C++】面向對象編程核心解析|五周目

面向對象編程(OOP)#

文章目錄#


面向對象編程#

面向對象編程(Object-Oriented Programming, OOP) 是一種以對象為中心的程序設計範式。它將現實世界中的事物抽象為程序中的對象,使用來定義這些對象的結構和行為。類封裝了對象的屬性(數據)和方法(行為),並通過繼承多態封裝等機制實現代碼的復用、靈活性和可維護性。OOP的核心思想是模擬現實世界的結構,通過模塊化設計提高程序的可擴展性和可讀性。


類和對象#

通俗解釋#

  • :類似於藍圖或模板,描述了一類事物的共性。例如,“汽車”是一個類,定義了汽車的屬性(如品牌、顏色、速度)和行為(如行駛、刹車)。類本身並不是具體的實體,只是規範了對象應該具有的特征和功能。
  • 對象:對象是類的具體實例。比如,“一輛紅色的寶馬汽車”是一個對象,它根據“汽車”類創建,擁有具體的屬性值(如品牌=寶馬,顏色=紅色)和行為。對象是程序中實際操作的實體,占用內存空間。

專業解釋#

  • :類是對一組具有相同屬性和行為的對象的抽象描述。它定義了對象的數據結構(屬性)和操作(方法)。類不占用內存空間,僅作為模板存在。
  • 對象:對象是類的實例化結果,擁有獨立的內存地址和屬性值。對象通過類的構造函數創建,並可以通過方法操作其屬性或執行特定行為。

類的基本組成#

在C++中,類由以下幾個核心部分組成:類名訪問修飾符成員變量(屬性)成員函數(方法)。此外,類還包括特殊的成員函數,如構造函數析構函數

類名#

類名是類的唯一標識符,用於區分不同的類。類名應遵循C++命名規則,通常使用清晰且有意義的名稱。例如:

class Person {
};

訪問修飾符#

訪問修飾符控制類成員的訪問權限,C++提供了三種修飾符:

  • public:成員可在類內外訪問,常用於定義外部接口。
  • protected:成員可在類內及其派生類中訪問,但不可在類外部直接訪問。
  • private:成員僅限類內部訪問,外部和派生類無法直接訪問(除非通過公共接口)。

示例:

class Person {
public:
int publicVar; // 可公開訪問
protected:
int protectedVar; // 僅類內和派生類可訪問
private:
int privateVar; // 僅類內可訪問
};

成員變量(屬性)#

成員變量用於存儲對象的狀態數據,可以是任何有效的C++數據類型(如intstd::string、自定義類型等)。通常,成員變量被設置為privateprotected,以通過方法進行訪問和修改,實現數據封裝。

示例:

#include <string>
class Person {
private:
std::string name; // 姓名
int age; // 年齡
public:
// 方法將在後面定義
};

成員函數(方法)#

成員函數定義了對象的行為,可以訪問和操作類的成員變量。成員函數的語法為:

返回類型 函數名(參數列表) { 函數體 }

若函數被聲明為const,則表示它不能修改成員變量(除非變量被聲明為mutable):

返回類型 函數名(參數列表) const { 函數體 }
構造函數#

構造函數用於初始化對象,在對象創建時自動調用。其名稱與類名相同,無返回類型。可以使用初始化列表高效初始化成員變量:

類名(參數列表) : 屬性1(值1), 屬性2(值2) { 函數體 }
析構函數#

析構函數用於在對象銷毀時執行清理操作(如釋放內存)。其名稱為~類名(),無參數且無返回類型:

~類名() { 函數體 }
示例代碼#

以下是一個完整的Person類示例,展示構造函數、析構函數和成員函數的使用:

#include <iostream>
#include <string>
class Person {
private:
std::string name;
int age;
public:
// 構造函數
Person(std::string name_value, int age_value) : name(name_value), age(age_value) {
std::cout << "Created Person: " << name << ", age: " << age << std::endl;
}
// 析構函數
~Person() {
std::cout << "Destroyed Person: " << name << ", age: " << age << std::endl;
}
// 成員函數:獲取姓名(const方法)
std::string getName() const {
return name;
}
// 成員函數:獲取年齡(const方法)
int getAge() const {
return age;
}
// 成員函數:設置年齡
void setAge(int age_value) {
age = age_value;
std::cout << "Age updated to: " << age << std::endl;
}
// 成員函數:顯示信息(const方法)
void displayInfo() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
int main() {
Person* person1 = new Person("SanZhang", 30);
person1->displayInfo();
person1->setAge(31);
person1->displayInfo();
Person* person2 = new Person("SiLi", 25);
person2->displayInfo();
delete person1; // 調用析構函數
delete person2; // 調用析構函數
return 0;
}

輸出:

Created Person: SanZhang, age: 30
Name: SanZhang, Age: 30
Age updated to: 31
Name: SanZhang, Age: 31
Created Person: SiLi, age: 25
Name: SiLi, Age: 25
Destroyed Person: SanZhang, age: 31
Destroyed Person: SiLi, age: 25

面向對象編程的四大機制#

封裝#

封裝將數據(屬性)和操作數據的方法封裝到一個類中,並通過訪問修飾符(publicprotectedprivate)控制訪問權限。封裝隱藏了對象的內部實現細節,僅暴露必要的接口,從而提高代碼的安全性和可維護性。

示例分析: 在上述Person類中:

  • nameage被聲明為private,防止外部直接訪問。
  • 通過public方法(如getNamesetAge)提供受控訪問,確保數據修改符合邏輯(例如,檢查age是否為正數)。

補充說明: 封裝的好處包括:

  • 數據保護:防止外部代碼直接修改對象狀態,減少錯誤。
  • 模塊化:內部實現可以獨立修改而不影響外部代碼。
  • 接口簡化:外部只需關注公開接口,無需了解內部細節。

繼承#

繼承允許一個新類(派生類/子類)從現有類(基類/父類)繼承屬性和方法,並可擴展或重寫功能。繼承實現了代碼復用和層次化設計。C++中的繼承語法為:

class 派生類 : 訪問修飾符 基類

示例: 創建Student類,繼承自Person類,添加學號屬性和專屬方法:

#include <iostream>
#include <string>
class Person {
private:
std::string name;
int age;
public:
Person(std::string name_value, int age_value) : name(name_value), age(age_value) {
std::cout << "Created Person: " << name << ", age: " << age << std::endl;
}
virtual ~Person() {
std::cout << "Destroyed Person: " << name << ", age: " << age << std::endl;
}
std::string getName() const { return name; }
int getAge() const { return age; }
void setAge(int age_value) {
age = age_value;
std::cout << "Age updated to: " << age << std::endl;
}
virtual void displayInfo() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
class Student : public Person {
private:
std::string studentId;
public:
Student(std::string name_value, int age_value, std::string id)
: Person(name_value, age_value), studentId(id) {
std::cout << "Created Student with ID: " << studentId << std::endl;
}
~Student() {
std::cout << "Destroyed Student with ID: " << studentId << std::endl;
}
std::string getStudentId() const { return studentId; }
void displayInfo() const override {
std::cout << "Student: Name: " << getName() << ", Age: " << getAge()
<< ", ID: " << studentId << std::endl;
}
};
int main() {
Student* student = new Student("SanZhang", 20, "A12138");
student->displayInfo();
student->setAge(21);
delete student;
return 0;
}

輸出:

Created Person: SanZhang, age: 20
Created Student with ID: A12138
Student: Name: SanZhang, Age: 20, ID: A12138
Age updated to: 21
Destroyed Student with ID: A12138
Destroyed Person: SanZhang, age: 21

補充說明

  • 繼承類型:C++支持publicprotectedprivate繼承,影響派生類對基類成員的訪問權限。
  • 虛析構函數:基類析構函數應聲明為virtual,確保通過基類指針刪除派生類對象時正確調用派生類析構函數。
  • 代碼復用:繼承避免了重複定義通用屬性和方法,提高了代碼效率。

多態#

多態允許不同類型的對象通過統一接口執行不同的行為。C++中的多態分為:

  • 靜態多態:通過函數重載或模板實現,編譯時確定行為。
  • 動態多態:通過虛函數和繼承實現,運行時確定行為(更常見於OOP討論)。

動態多態依賴虛函數(使用virtual關鍵字)和向上轉型(派生類對象賦值給基類指針或引用)。這允許通過基類接口調用派生類的具體實現。

示例

#include <iostream>
#include <string>
class Person {
protected:
std::string name;
int age;
public:
Person(std::string name_value, int age_value) : name(name_value), age(age_value) {
std::cout << "Created Person: " << name << ", age: " << age << std::endl;
}
virtual ~Person() {
std::cout << "Destroyed Person: " << name << ", age: " << age << std::endl;
}
virtual void displayInfo() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
};
class Student : public Person {
private:
std::string studentId;
public:
Student(std::string name_value, int age_value, std::string id)
: Person(name_value, age_value), studentId(id) {
std::cout << "Created Student with ID: " << studentId << std::endl;
}
~Student() {
std::cout << "Destroyed Student with ID: " << studentId << std::endl;
}
void displayInfo() const override {
std::cout << "Student: Name: " << name << ", Age: " << age
<< ", ID: " << studentId << std::endl;
}
};
void displayInfo(const Person* person) {
person->displayInfo();
}
int main() {
Person* person = new Person("SiLi", 35);
Person* student = new Student("SanZhang", 20, "A12138");
displayInfo(person); // 調用Person的displayInfo
displayInfo(student); // 調用Student的displayInfo
delete person;
delete student;
return 0;
}

輸出:

Created Person: SiLi, age: 35
Created Person: SanZhang, age: 20
Created Student with ID: A12138
Name: SiLi, Age: 35
Student: Name: SanZhang, Age: 20, ID: A12138
Destroyed Person: SiLi, age: 35
Destroyed Student with ID: A12138
Destroyed Person: SanZhang, age: 20

補充說明

  • 虛函數:使用virtual關鍵字聲明,派生類可通過override重寫,實現運行時多態。
  • 虛析構函數:防止通過基類指針刪除派生類對象時的未定義行為。
  • 運行時多態:通過虛函數表(vtable)實現,運行時根據對象實際類型調用相應方法。

抽象#

抽象是將現實世界的實體或概念簡化為程序中的類,提取共性並忽略細枝末節。抽象類通過定義純虛函數(virtual 函數名() = 0)提供通用接口,無法實例化,只能作為基類供派生類實現。

純虛函數

  • 在基類中聲明,無實現(= 0)。
  • 派生類必須重寫純虛函數,否則也成為抽象類。

示例

#include <iostream>
#include <string>
class Person {
protected:
std::string name;
int age;
public:
Person(std::string name_value, int age_value) : name(name_value), age(age_value) {
std::cout << "Created Person: " << name << ", age: " << age << std::endl;
}
virtual ~Person() {
std::cout << "Destroyed Person: " << name << ", age: " << age << std::endl;
}
virtual void displayInfo() const = 0; // 純虛函數
};
class Student : public Person {
private:
std::string studentId;
public:
Student(std::string name_value, int age_value, std::string id)
: Person(name_value, age_value), studentId(id) {
std::cout << "Created Student with ID: " << studentId << std::endl;
}
~Student() {
std::cout << "Destroyed Student with ID: " << studentId << std::endl;
}
void displayInfo() const override {
std::cout << "Student: Name: " << name << ", Age: " << age
<< ", ID: " << studentId << std::endl;
}
};
class Teacher : public Person {
private:
std::string subject;
public:
Teacher(std::string name_value, int age_value, std::string subj)
: Person(name_value, age_value), subject(subj) {
std::cout << "Created Teacher for subject: " << subject << std::endl;
}
~Teacher() {
std::cout << "Destroyed Teacher for subject: " << subject << std::endl;
}
void displayInfo() const override {
std::cout << "Teacher: Name: " << name << ", Age: " << age
<< ", Subject: " << subject << std::endl;
}
};
void displayInfo(const Person* person) {
person->displayInfo();
}
int main() {
// Person person("SiLi", 35); // 錯誤:抽象類無法實例化
Person* student = new Student("SanZhang", 20, "A12138");
Person* teacher = new Teacher("SiLi", 35, "C++ Programming");
displayInfo(student);
displayInfo(teacher);
delete student;
delete teacher;
return 0;
}

輸出:

Created Person: SanZhang, age: 20
Created Student with ID: A12138
Created Person: SiLi, age: 35
Created Teacher for subject: C++ Programming
Student: Name: SanZhang, Age: 20, ID: A12138
Teacher: Name: SiLi, Age: 35, Subject: C++ Programming
Destroyed Student with ID: A12138
Destroyed Person: SanZhang, age: 20
Destroyed Teacher for subject: C++ Programming
Destroyed Person: SiLi, age: 35

補充說明

  • 抽象類的作用:定義通用接口,強制派生類實現特定行為,適用於需要統一規範的場景。
  • 純虛函數:確保派生類提供具體實現,增強代碼的靈活性和可擴展性。
  • 應用場景:如設計框架、插件系統,抽象類提供接口規範,派生類實現具體邏輯。

補充內容#

  1. OOP的優勢

    • 模塊化:將功能封裝到類中,便於維護和擴展。
    • 可復用性:通過繼承和多態減少代碼重複。
    • 靈活性:多態和抽象允許程序適應不同需求。
    • 可維護性:封裝隱藏實現細節,降低耦合度。
  2. C++特有的OOP特性

    • 多重繼承:C++支持類繼承多個基類(需謹慎使用,避免歧義)。
    • 運算符重載:允許自定義運算符行為,增強類的表現力。
    • 模板:結合OOP實現泛型編程,提升代碼靈活性。
  3. 注意事項

    • 內存管理:動態分配對象時,需使用delete釋放內存,防止內存洩漏。
    • 虛函數開銷:虛函數引入vtable,增加少量運行時開銷。
    • 抽象類設計:純虛函數應只定義必要接口,避免過多抽象導致設計複雜。

總結

本文詳細介紹了面向對象編程(OOP)的核心概念,包括類和對象的基本組成,以及封裝、繼承、多態和抽象四大機制。通過C++示例代碼,展示了如何實現這些機制,並補充了專業解釋和應用場景。OOP通過模塊化、層次化和靈活的設計,顯著提高了代碼的可維護性和可擴展性,是現代軟件開發的基石。

🎓【C++】面向對象編程核心解析|五周目
https://illumi.love/posts/指南向/c面向對象編程核心解析/
作者
Illumi糖糖
發布於
2025-07-18
許可協議
🔒CC BY-NC-ND 4.0