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

