C++類與this指針
1.類
1.1.什麼是類?
class Name
{
// 類體:由成員函數和成員變量組成
};
上述代碼中:class爲定義類的關鍵字,Name爲類的名字,{}中爲類的主體,注意:類定義結束時後面分號。
類中的元素稱爲類的成員;類中的數據稱爲類的屬性或成員變量;類中的函數稱爲類的方法或成員函數。
類的兩種定義方式:
1. 聲明和定義全部放在類體中。注意:成員函數如果在類中定義,編譯器可能會將其當成內聯函數處理。
2.聲明放在.h文件中,類的定義放在.cpp文件中 。
注:在一般情況下,更期望使用第二種方式
1.2.訪問限定符
C++實現封裝的方式:用類將對象的屬性與方法結合在一塊,讓對象更加完善,通過訪問權限選擇性的將其接口提供給外部的用戶使用。
訪問限定符說明:
1. public修飾的成員在類外可以直接被訪問;
2. protected和private修飾的成員在類外不能直接被訪問(此處protected和private是類似的);
3. 訪問權限作用域從該訪問限定符出現的位置開始直到下一個訪問限定符出現時爲止;
4. class的默認訪問權限爲private,struct爲public(因爲struct要兼容C)。
【面試題】
問題:C++中struct和class的區別是什麼?
解答:C++需要兼容C語言,所以C++中struct可以當成結構體去使用。另外C++中struct還可以用來定義類。和class是定義類是一樣的,區別是struct的成員默認訪問方式是public,class中是struct的成員默認訪問方式是private。
1.3.封裝
什麼是封裝?
封裝:將數據和操作數據的方法進行有機結合,隱藏對象的屬性和實現細節,僅對外公開接口來和對象進行交互。
封裝本質上是一種管理:我們使用類數據和方法都封裝到一下。不想被別人看到的,我們使用protected/private把成員封裝起來。開放一些共有的成員函數對成員合理的訪問。所以封裝本質是一種管理。
【面試題】
面向對象的三大特性:封裝、繼承、多態。
2.this指針
2.1.什麼是this指針?
我們首先來定義一個日期類Date:
class Date
{
public:
void Display()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
// 建議成員變量加"_"
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1, d2;
d1.SetDate(2020, 4, 1);
d2.SetDate(2020, 4, 2);
d1.Display();
d2.Display();
return 0;
} // 日期類
問:Date類中有SetDate與Display兩個成員函數,函數體中沒有關於不同對象的區分,但是當s1調用SetDate函數時,函數是怎樣知道應該設置s1對象,而不是設置s2對象呢?
答:在C++中通過引入this指針解決該問題,即:C++編譯器給每個“非靜態的成員函數“增加了一個隱藏的指針參數,讓該指針指向當前對象(函數運行時調用該函數的對象),在函數體中所有成員變量的操作,都是通過該指針去訪問。只不過所有的操作對用戶都是透明的,即用戶不需要來傳遞,編譯器自動完成。
2.2.this指針的特性
1. this指針的類型:類類型 *const
2. 只能在成員函數的內部使用
3. this指針本質上其實是一個成員函數的形參,是對象調用成員函數時,將對象地址作爲實參傳遞給this形參。所以對象中不存儲this指針。
4. this指針是成員函數第一個隱含的指針形參,一般情況由編譯器通過ecx寄存器自動傳遞,不需要用戶傳遞。
【面試題】
1. this指針存在哪裏?
A.棧 B.堆 C.數據段 D.代碼段 E.對象中
答:A,this指針是隱含的形參(但是在一些地方也會存在寄存器中,在VS下通過寄存器ecx傳遞,來提高效率)。
2. this指針可以爲空嗎?
可以爲空,當我們在調用函數的時候,如果函數內部並不需要使用this,也就是不需要通過this指向當前對象並對其進行操作時可以爲空(定義一個空函數或在裏面隨便打印一個字符串),如果調用的函數需要指向當前對象,並進行操作,則會發生錯誤(空指針引用)就跟C中一樣不能進行空指針的引用。(下題對此問題進行了解答)
3.請看下面程序,程序能編譯通過嗎?
下面程序會崩潰嗎?在哪裏崩潰?
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
void Show()
{
cout << "Show()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA(); // 崩潰
p->Show(); // 正常運行
// 因爲p->Show()沒有對this指針進行解引用
}
答:程序不能通過,會在調用p->PrintA()函數並進行訪問成員變量時,函數會崩潰。
解析:p是一個空指針,只有在空指針解引用時會崩潰。在函數 p->PrintA()中,this是一個空指針,當它訪問成員變量_a時,會進行解引用,所以程序會崩潰;而在函數p->Show()中,由於函數都存在公共代碼段,不在對象中,所以this沒有指針進行解引用,程序正常運行。