C++中空指針訪問成員函數(shù)的實(shí)現(xiàn)
一、核心結(jié)論先明確
空指針(nullptr/NULL)可以調(diào)用類的非靜態(tài)成員函數(shù),但有一個(gè)嚴(yán)格前提:
函數(shù)內(nèi)部沒有通過this指針訪問任何非靜態(tài)成員變量 / 調(diào)用依賴成員變量的函數(shù)。
一旦訪問成員變量,就會(huì)觸發(fā) “空指針解引用”,程序直接崩潰(段錯(cuò)誤)。
二、代碼示例:空指針調(diào)用成員函數(shù)的兩種情況
- 能正常調(diào)用的情況(函數(shù)內(nèi)不訪問成員變量)
#include <iostream>
using namespace std;
class Person {
public:
int age; // 非靜態(tài)成員變量
// 情況1:成員函數(shù)僅打印固定內(nèi)容,不訪問任何成員變量
void showHello() {
cout << "Hello, this is a member function!" << endl;
}
// 情況2:靜態(tài)成員函數(shù)(無this指針,和空指針無關(guān))
static void showStatic() {
cout << "Hello, this is a static member function!" << endl;
}
};
int main() {
// 定義空指針
Person* p = nullptr;
// 1. 空指針調(diào)用不訪問成員變量的非靜態(tài)成員函數(shù) → 正常執(zhí)行
p->showHello();
// 2. 空指針調(diào)用靜態(tài)成員函數(shù) → 正常執(zhí)行(靜態(tài)函數(shù)無this)
p->showStatic();
// 更規(guī)范的寫法:Person::showStatic(); (靜態(tài)函數(shù)優(yōu)先用類名調(diào)用)
return 0;
}
- 調(diào)用后崩潰的情況(函數(shù)內(nèi)訪問成員變量)
#include <iostream>
using namespace std;
class Person {
public:
int age;
// 函數(shù)內(nèi)訪問成員變量(會(huì)通過this->age訪問)
void showAge() {
cout << "Age: " << this->age << endl; // 等價(jià)于 cout << age;
}
};
int main() {
Person* p = nullptr;
p->showAge(); // 運(yùn)行崩潰!空指針解引用
return 0;
}
崩潰原因:
調(diào)用p->showAge()時(shí),編譯器會(huì)把p(空指針)作為this指針傳入函數(shù),函數(shù)內(nèi)this->age等價(jià)于(nullptr).age—— 對空指針解引用,觸發(fā)內(nèi)存訪問錯(cuò)誤(段錯(cuò)誤)。
三、底層原因:成員函數(shù)的存儲(chǔ)與 this 指針
要理解這個(gè)現(xiàn)象,必須回到 C++ 對象模型和this指針的本質(zhì):
- 成員函數(shù)的存儲(chǔ):所有非靜態(tài)成員函數(shù)都存儲(chǔ)在代碼段(全局共享),不屬于任何對象,對象的內(nèi)存中只存成員變量;
- 調(diào)用成員函數(shù)的本質(zhì):p->func()的邏輯是:
- 找到Person類的func函數(shù)在代碼段的地址;
- 把p的地址作為this指針傳入func;
執(zhí)行func的代碼。
空指針調(diào)用的關(guān)鍵:
- 如果func內(nèi)不使用this指針(不訪問成員變量),僅執(zhí)行固定邏輯,那么即使this是空指針,也能正常執(zhí)行(因?yàn)闆]解引用this);
- 如果func內(nèi)使用this指針(訪問成員變量),就會(huì)對空指針解引用,觸發(fā)崩潰。
四、易踩坑的細(xì)節(jié)補(bǔ)充
const 成員函數(shù)也不例外:
const成員函數(shù)只是把this限定為const Person const,但如果this是空指針,訪問成員變量依然崩潰:
void showAge() const {
cout << age << endl; // 崩潰!this是空指針,this->age非法
}
空指針調(diào)用虛函數(shù)的特殊情況:
虛函數(shù)調(diào)用依賴this指針指向的虛表指針(vptr),空指針沒有 vptr,因此調(diào)用虛函數(shù)會(huì)直接崩潰(無論是否訪問成員變量):
class Person {
public:
virtual void showHello() { // 虛函數(shù)
cout << "Hello" << endl;
}
};
int main() {
Person* p = nullptr;
p->showHello(); // 直接崩潰!需要訪問this->vptr
return 0;
}
語法合法但邏輯非法:
空指針調(diào)用成員函數(shù)在語法上是允許的(編譯器不報(bào)錯(cuò)),但邏輯上是錯(cuò)誤的 —— 除非你明確知道函數(shù)內(nèi)不訪問成員變量,否則絕對不要這么寫。
總結(jié)
空指針可以調(diào)用非靜態(tài)、非虛、且不訪問成員變量的成員函數(shù)(語法合法,運(yùn)行不崩潰);
空指針調(diào)用訪問成員變量的成員函數(shù) / 虛函數(shù)會(huì)崩潰(本質(zhì)是對空指針解引用);
核心原因:成員函數(shù)存在于代碼段,調(diào)用僅需傳入this指針;是否崩潰取決于是否使用this指針訪問內(nèi)存。
開發(fā)建議:永遠(yuǎn)不要用空指針調(diào)用成員函數(shù)!即使語法上能運(yùn)行,也是不規(guī)范、易出錯(cuò)的寫法,可在函數(shù)開頭加assert(this != nullptr)做校驗(yàn),提前暴露問題。
到此這篇關(guān)于C++中空指針訪問成員函數(shù)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++ 空指針訪問內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++求解二叉樹的下一個(gè)結(jié)點(diǎn)問題
本文將通過C++求解以下問題:給定一個(gè)二叉樹其中的一個(gè)結(jié)點(diǎn),請找出中序遍歷順序的下一個(gè)結(jié)點(diǎn)并且返回。文中示例代碼講解詳細(xì),感興趣的可以了解一下2022-04-04
C語言數(shù)據(jù)結(jié)構(gòu)與算法之圖的遍歷(二)
這篇文章主要是介紹了利用廣度優(yōu)先算法實(shí)現(xiàn)圖的遍歷,文中利用圖文詳細(xì)的介紹了實(shí)現(xiàn)步驟,對我們學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法有一定的幫助,需要的朋友可以參考一下2021-12-12
C++ 創(chuàng)建桌面快捷方式 開始菜單的實(shí)現(xiàn)代碼
這篇文章介紹了C++ 創(chuàng)建桌面快捷方式,開始菜單的實(shí)現(xiàn)代碼,需要的朋友可以參考一下2013-06-06
C++對string進(jìn)行大小寫轉(zhuǎn)換操作方法
這篇文章主要介紹了C++對string進(jìn)行大小寫轉(zhuǎn)換操作方法,本文通過兩種方法結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02

