C++ 類和對象從基礎(chǔ)語法到高級(jí)特性深度解析
在 C++ 編程中,類和對象是面向?qū)ο缶幊蹋∣OP)的核心基石,封裝、繼承、多態(tài)三大特性均圍繞其展開。本文將從類的定義與實(shí)例化、默認(rèn)成員函數(shù)、高級(jí)特性等維度,結(jié)合實(shí)戰(zhàn)代碼,系統(tǒng)梳理類和對象的關(guān)鍵知識(shí)點(diǎn),幫助開發(fā)者夯實(shí) OOP 基礎(chǔ)。
一、類的基礎(chǔ)認(rèn)知:定義、訪問控制與實(shí)例化
1.1 類的定義格式
C++ 使用class關(guān)鍵字定義類(struct也可定義類,兼容 C 語言用法且支持成員函數(shù)),類體包含成員變量(屬性)和成員函數(shù)(方法),結(jié)束時(shí)必須加分號(hào)。為區(qū)分成員變量與局部變量,慣例是給成員變量加前綴(如_)或后綴,例如_year、m_month。
class Date {
public:
// 成員函數(shù):初始化日期
void Init(int year, int month, int day) {
_year = year;
_month = month;
_day = day;
}
private:
// 成員變量:加前綴_區(qū)分
int _year;
int _month;
int _day;
}; // 分號(hào)不可省略1.2 訪問限定符:封裝的核心實(shí)現(xiàn)
訪問限定符控制成員的訪問權(quán)限,是封裝特性的直接體現(xiàn):
public:類外可直接訪問(通常暴露接口函數(shù));private/protected:類外不可直接訪問(通常隱藏成員變量,繼承時(shí)二者有差異);- 訪問權(quán)限作用域:從限定符出現(xiàn)位置到下一個(gè)限定符結(jié)束,
class默認(rèn)private,struct默認(rèn)public。
1.3 類域與成員函數(shù)分離
類定義了獨(dú)立的作用域,類外實(shí)現(xiàn)成員函數(shù)時(shí)需用::作用域操作符指明所屬類,否則編譯器會(huì)視為全局函數(shù)。
// 類內(nèi)聲明,類外實(shí)現(xiàn)
void Date::Init(int year, int month, int day) {
_year = year;
_month = month;
_day = day;
}1.4 類的實(shí)例化
類是對象的 “設(shè)計(jì)圖”,僅聲明成員變量(未分配空間),實(shí)例化是通過類創(chuàng)建對象并分配物理內(nèi)存的過程。一個(gè)類可實(shí)例化多個(gè)對象,每個(gè)對象擁有獨(dú)立的成員變量存儲(chǔ)空間,成員函數(shù)則共享(存儲(chǔ)在代碼段)。
int main() {
Date d1; // 實(shí)例化對象d1,分配內(nèi)存
d1.Init(2024, 10, 1); // 調(diào)用成員函數(shù)初始化
return 0;
}1.5 對象大小計(jì)算
對象僅存儲(chǔ)成員變量,大小遵循內(nèi)存對齊規(guī)則(與結(jié)構(gòu)體一致),目的是提高訪問效率:
- 第一個(gè)成員偏移量為 0;
- 其他成員對齊到 “對齊數(shù)”(編譯器默認(rèn)值與成員大小的較小值,VS 默認(rèn) 8)的整數(shù)倍;
- 總大小為最大對齊數(shù)的整數(shù)倍;
- 無成員變量的類對象大小為 1 字節(jié)(占位標(biāo)識(shí)對象存在)。
class A {
private:
char _ch; // 1字節(jié)
int _i; // 4字節(jié),對齊數(shù)4
};
// 內(nèi)存對齊后大?。?字節(jié)(1+3填充+4)
cout << sizeof(A) << endl; // 輸出8二、this 指針:對象的 “隱藏身份標(biāo)識(shí)”
2.1 核心問題
多個(gè)對象共享成員函數(shù),函數(shù)如何區(qū)分操作的是哪個(gè)對象?例如d1.Init()和d2.Init(),函數(shù)需知道當(dāng)前操作的是d1還是d2。
2.2 本質(zhì)與特性
C++ 編譯器在成員函數(shù)形參第一個(gè)位置隱含添加this指針(類型為類名* const),指向當(dāng)前調(diào)用函數(shù)的對象,函數(shù)體內(nèi)訪問成員變量本質(zhì)是通過this指針訪問(可顯式使用,不可顯式聲明)。
// 編譯器優(yōu)化后的Init函數(shù)原型
void Date::Init(Date* const this, int year, int month, int day) {
this->_year = year; // 顯式使用this
_month = month; // 隱式使用this
}
// 調(diào)用時(shí)編譯器自動(dòng)傳遞對象地址
d1.Init(2024, 10, 1); // 等價(jià)于d1.Init(&d1, 2024, 10, 1)2.3 經(jīng)典面試題解析
// 題目1:編譯運(yùn)行結(jié)果?
class A {
public:
void Print() { cout << "A::Print()" << endl; }
private:
int _a;
};
int main() {
A* p = nullptr;
p->Print(); // 正常運(yùn)行:Print未訪問成員變量,無需解引用p
return 0;
}
// 題目2:編譯運(yùn)行結(jié)果?
class A {
public:
void Print() { cout << _a << endl; } // 訪問成員變量,需解引用this
private:
int _a;
};
int main() {
A* p = nullptr;
p->Print(); // 運(yùn)行崩潰:this為nullptr,解引用出錯(cuò)
return 0;
}三、默認(rèn)成員函數(shù):編譯器的 “自動(dòng)實(shí)現(xiàn)”
當(dāng)用戶未顯式定義時(shí),編譯器會(huì)自動(dòng)生成 6 個(gè)默認(rèn)成員函數(shù),核心是前 4 個(gè):構(gòu)造、析構(gòu)、拷貝構(gòu)造、賦值重載。
3.1 構(gòu)造函數(shù):對象的 “初始化器”
- 功能:替代
Init函數(shù),對象實(shí)例化時(shí)自動(dòng)調(diào)用,初始化成員變量; - 特性:
- 函數(shù)名與類名相同,無返回值(無需寫
void); - 可重載(無參、帶參、全缺省);
- 無顯式定義時(shí),編譯器生成默認(rèn)構(gòu)造(對內(nèi)置類型不初始化,自定義類型調(diào)用其默認(rèn)構(gòu)造);
- 無參、全缺省、編譯器默認(rèn)生成的構(gòu)造,統(tǒng)稱 “默認(rèn)構(gòu)造”(不傳參即可調(diào)用)。
- 函數(shù)名與類名相同,無返回值(無需寫
class Date {
public:
// 全缺省構(gòu)造(推薦,兼顧多種初始化場景)
Date(int year = 1, int month = 1, int day = 1) {
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
// 實(shí)例化方式
Date d1; // 調(diào)用全缺省構(gòu)造,默認(rèn)1-1-1
Date d2(2024, 10, 1); // 調(diào)用帶參構(gòu)造3.2 析構(gòu)函數(shù):對象的 “清理工”
- 功能:替代
Destroy函數(shù),對象生命周期結(jié)束時(shí)自動(dòng)調(diào)用,釋放資源(如堆內(nèi)存); - 特性:
- 函數(shù)名
~類名,無參數(shù)無返回值; - 一個(gè)類僅一個(gè)析構(gòu)函數(shù)(不可重載);
- 無顯式定義時(shí),編譯器生成默認(rèn)析構(gòu)(對內(nèi)置類型不處理,自定義類型調(diào)用其析構(gòu));
- 有資源申請(如
malloc、new)時(shí)必須顯式定義,否則內(nèi)存泄漏。
- 函數(shù)名
class Stack {
public:
Stack(int n = 4) {
_a = (int*)malloc(sizeof(int) * n);
_capacity = n;
_top = 0;
}
// 顯式定義析構(gòu),釋放堆內(nèi)存
~Stack() {
free(_a);
_a = nullptr;
_top = _capacity = 0;
}
private:
int* _a;
size_t _capacity;
size_t _top;
};3.3 拷貝構(gòu)造函數(shù):對象的 “復(fù)制器”
- 功能:用已有對象初始化新對象(如
Date d2 = d1); - 特性:
- 第一個(gè)參數(shù)必須是
const 類名&(傳值會(huì)引發(fā)無窮遞歸),后續(xù)參數(shù)可帶默認(rèn)值; - 無顯式定義時(shí),編譯器生成默認(rèn)拷貝構(gòu)造(內(nèi)置類型值拷貝 / 淺拷貝,自定義類型調(diào)用其拷貝構(gòu)造);
- 淺拷貝問題:若成員變量指向堆內(nèi)存(如
Stack的_a),會(huì)導(dǎo)致多個(gè)對象共享同一塊內(nèi)存,析構(gòu)時(shí)重復(fù)釋放崩潰,需顯式實(shí)現(xiàn)深拷貝。
- 第一個(gè)參數(shù)必須是
Stack::Stack(const Stack& st) {
// 深拷貝:為新對象分配獨(dú)立內(nèi)存
_a = (int*)malloc(sizeof(int) * st._capacity);
if (_a == nullptr) perror("malloc fail");
memcpy(_a, st._a, sizeof(int) * st._top);
_top = st._top;
_capacity = st._capacity;
}3.4 賦值運(yùn)算符重載:對象的 “賦值器”
- 功能:兩個(gè)已存在對象間的賦值(如
d1 = d2),區(qū)別于拷貝構(gòu)造(初始化新對象); - 特性:
- 必須重載為成員函數(shù),函數(shù)原型
類名& operator=(const 類名&); - 返回
類名&支持連續(xù)賦值(如d1 = d2 = d3); - 需檢查自賦值(
if (this != &d)),避免重復(fù)釋放; - 無顯式定義時(shí),編譯器生成默認(rèn)賦值重載(淺拷貝,需資源的類需顯式實(shí)現(xiàn)深拷貝)。
- 必須重載為成員函數(shù),函數(shù)原型
Date& Date::operator=(const Date& d) {
if (this != &d) { // 避免自賦值
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this; // 支持連續(xù)賦值
}四、高級(jí)特性:提升代碼靈活性與效率
4.1 初始化列表:成員變量的 “初始化源頭”
- 格式:構(gòu)造函數(shù)后加
:,后跟成員變量初始化表達(dá)式(成員變量(值), ...); - 必要性:引用成員、
const成員、無默認(rèn)構(gòu)造的自定義類型成員,必須通過初始化列表初始化; - 注意:初始化順序與類中成員聲明順序一致,與列表順序無關(guān)。
class Date {
public:
// 初始化列表初始化
Date(int year, int month, int day, int& ref)
: _year(year)
, _month(month)
, _day(day)
, _ref(ref) // 引用必須初始化
, _n(10) // const成員必須初始化
{}
private:
int _year;
int _month;
int _day;
int& _ref; // 引用成員
const int _n; // const成員
};4.2 static 成員:類的 “共享資源”
- 靜態(tài)成員變量:
- 用
static修飾,所有對象共享,存儲(chǔ)在靜態(tài)區(qū); - 類內(nèi)聲明,類外初始化(
類型 類名::變量名 = 值); - 受訪問限定符控制,可通過
類名::變量或對象.變量訪問。
- 用
- 靜態(tài)成員函數(shù):
- 用
static修飾,無this指針; - 僅可訪問靜態(tài)成員變量 / 函數(shù),不可訪問非靜態(tài)成員。
- 用
應(yīng)用場景:統(tǒng)計(jì)對象創(chuàng)建個(gè)數(shù):
class A {
public:
A() { ++_scount; }
A(const A&) { ++_scount; }
~A() { --_scount; }
static int GetCount() { return _scount; } // 靜態(tài)成員函數(shù)
private:
static int _scount; // 靜態(tài)成員變量
};
int A::_scount = 0; // 類外初始化
int main() {
A a1, a2;
cout << A::GetCount() << endl; // 輸出2
return 0;
}4.3 友元:突破封裝的 “特殊權(quán)限”
友元允許外部函數(shù) / 類訪問類的私有成員,分為友元函數(shù)和友元類,慎用(破壞封裝)。
- 友元函數(shù):非成員函數(shù),類內(nèi)聲明時(shí)加
friend; - 友元類:類 A 是類 B 的友元,則 A 的所有成員函數(shù)可訪問 B 的私有成員(單向關(guān)系,不可傳遞)。
class Date {
// 友元聲明:operator<<可訪問私有成員
friend ostream& operator<<(ostream& out, const Date& d);
private:
int _year;
int _month;
int _day;
};
// 全局函數(shù)實(shí)現(xiàn)
ostream& operator<<(ostream& out, const Date& d) {
out << d._year << "-" << d._month << "-" << d._day;
return out;
}
// 使用
Date d(2024, 10, 1);
cout << d << endl; // 輸出2024-10-14.4 匿名對象:臨時(shí)使用的 “無名稱對象”
- 格式:
類名(實(shí)參),生命周期僅當(dāng)前行; - 場景:臨時(shí)調(diào)用成員函數(shù),無需定義命名對象。
class Solution {
public:
int Sum(int n) { return n*(n+1)/2; }
};
// 匿名對象調(diào)用函數(shù)
int ret = Solution().Sum(100); // 輸出5050五、C++ vs C 語言:封裝的優(yōu)勢
以Stack為例,對比 C 語言與 C++ 的實(shí)現(xiàn)差異:
| 特性 | C 語言實(shí)現(xiàn) | C++ 實(shí)現(xiàn) |
|---|---|---|
| 數(shù)據(jù)與函數(shù)關(guān)系 | 分離(函數(shù)需顯式傳結(jié)構(gòu)體指針) | 封裝(數(shù)據(jù) + 函數(shù)在類內(nèi),this 指針隱式傳遞) |
| 訪問控制 | 無,可直接修改結(jié)構(gòu)體成員 | 訪問限定符控制,私有成員不可直接修改 |
| 初始化與清理 | 需手動(dòng)調(diào)用Init/Destroy | 構(gòu)造 / 析構(gòu)函數(shù)自動(dòng)調(diào)用,避免遺漏 |
| 代碼簡潔性 | 需 typedef,函數(shù)參數(shù)繁瑣 | 類名直接作為類型,語法更簡潔 |
六、總結(jié)
類和對象是 C++ 面向?qū)ο缶幊痰暮诵模诵囊c(diǎn)可概括為:
- 封裝:通過類整合數(shù)據(jù)與函數(shù),訪問限定符控制權(quán)限;
- 默認(rèn)成員函數(shù):構(gòu)造(初始化)、析構(gòu)(清理)、拷貝構(gòu)造(復(fù)制新對象)、賦值重載(對象賦值)是基礎(chǔ),需區(qū)分使用場景;
- 高級(jí)特性:初始化列表解決特殊成員初始化,static 成員實(shí)現(xiàn)共享資源,友元靈活訪問私有成員(慎用),匿名對象簡化臨時(shí)操作;
- 內(nèi)存與效率:理解 this 指針、內(nèi)存對齊、編譯器拷貝優(yōu)化,避免內(nèi)存泄漏和性能問題。
到此這篇關(guān)于C++ 類和對象全解析:從基礎(chǔ)語法到高級(jí)特性的文章就介紹到這了,更多相關(guān)C++ 類和對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++/類與對象/默認(rèn)成員函數(shù)@構(gòu)造函數(shù)的用法
- C++類和對象之默認(rèn)成員函數(shù)的使用解讀
- C++類和對象之初始化列表的使用方式
- c++ rtti判斷基類指針指向的真實(shí)對象類型
- C++類與對象的重點(diǎn)知識(shí)點(diǎn)詳細(xì)分析
- C++類與對象的基礎(chǔ)知識(shí)點(diǎn)詳細(xì)分析
- c++重載運(yùn)算符時(shí)返回值為類的對象或者返回對象的引用問題
- C++淺析類與對象基礎(chǔ)點(diǎn)
- C++類與對象深入之引用與內(nèi)聯(lián)函數(shù)與auto關(guān)鍵字及for循環(huán)詳解
相關(guān)文章
C語言的常量,字符串,轉(zhuǎn)義字符,注釋你都了解嗎
這篇文章主要為大家詳細(xì)介紹了C語言的常量,字符串,轉(zhuǎn)義字符,注釋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02
c++優(yōu)先隊(duì)列(priority_queue)用法詳解
這篇文章主要介紹了c++優(yōu)先隊(duì)列(priority_queue)用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
C語言編程簡單卻重要的數(shù)據(jù)結(jié)構(gòu)順序表全面講解
這篇文章主要為大家介紹了C語言編程中非常簡單卻又非常重要的數(shù)據(jù)結(jié)構(gòu)順序表的全面講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-10-10
VSCode配置C++環(huán)境的方法步驟(MSVC)
這篇文章主要介紹了VSCode配置C++環(huán)境的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05

