標題:【C -> Cpp】由C邁向Cpp (6):靜態、友元和內部類
@水墨不寫bug
(圖片來源于網絡)
目錄
(一)靜態成員
(二)友元
?(三)內部類
(四)深入理解類和對象、總結
正文開始:?
(一)靜態成員
? ? ? ? C語言中有靜態的概念,比如靜態函數和靜態變量。
靜態變量:存儲在靜態區,隨著主函數的開始而創建并初始化,隨著程序結束而銷毀。選擇創建靜態變量,會使變量的生命周期延長到程序結束。
靜態函數則是不同的概念:靜態函數只能在當前源文件中訪問,不能被其他源文件訪問調用。選擇定義靜態函數的作用是將函數的作用域限制在當前源文件內,并且可以避免與其他源文件中定義的同名函數發生沖突。
? ? ? ? Cpp中,由于新增了類和對象的特性,對靜態變量的處理就有所不同了。
?????????類中是可以創建靜態變量的,由于靜態變量存儲在靜態區,只初始化一次,所以一個類(Class)內部(定義)包含有的靜態變量是可以通過任意一個這個Class創建的對象來訪問的,這也就表明了這個靜態變量是屬于這個類的,而不是單獨屬于某個實例化的對象。
? ? ? ? 如果我們執行下面這一段代碼:
#include<cstdlib>
#include<iostream>
using namespace std;
class A
{public:private:static int _a;int _b;int _c;
};
int main()
{A aa;cout << sizeof(aa) << endl;return 0;
}
?結果可能會讓你驚訝:靜態對象_a不是存儲在對象aa中的!
????????1.靜態成員為所有類對象所共享,不屬于某個具體的對象,存放在靜態區。
(類的成員函數指針也不存放在類內,而是存放在公共的代碼段)
?其次,類靜態對象的定義是在類外部的。
class A
{
public:private:static int _a;int _b;int _c;
};int A::_a = 5;
?????????2. 靜態成員變量必須在類外定義,定義時不添加static關鍵字,類中只是聲明
? ? ? ? ?訪問方式:
? ? ? ? 類靜態成員對象有兩種訪問方式:
? ? ? ? 1)通過實例化的對象訪問;
A aa;//實例化一個對象aa._a++;//通過對象訪問
? ? ? ? 2)通過類名訪問;
A::_a++;//直接通過類名訪問
????????3. 靜態成員函數沒有隱藏的this指針,不能訪問任何非靜態成員
>同時就是說:靜態成員函數只可以訪問靜態變量
?4. 靜態成員也是類的成員,受public、protected、private 訪問限定符的限制
(二)友元
? ? ? ? 友元是通過一個關鍵字(friend)來實現的;我們在實現一個類的時候,通常把成員函數定義為共有(public),而把成員變量定義為私有(private)。
????????如果我們在項目中想要通過重載cout來輸出自己的自定義類型對象時,一定會遇到這樣的問題:
ostream& operator<<(const Date d)
{out << this->_year << " " << this->_month << " " << this->_day;out << endl;return out;
}
? ? ? ? 由于用類對象調用重載后的函數時,參數的順序首先是this,其次是其他的對象。所以調用重載后的cout會十分的別扭,而與常規的邏輯不同:
cout<<d1;
? ? ? ? ?解決方法就是第一個參數必須是cout,其次是其他參數。由于類內部定義的函數的第一個參數必是this指針,所以這個邏輯正確的函數必須在類外定義。
? ? ? ? 但是由于類外的函數不能訪問類的private的成員函數,所以為了解決這一問題,Cpp就引入“友元”的概念:
? ? ? ? 成為友元的函數可以突破private的限制,直接訪問類的私有成員變量。
????????友元分為:#友元函數和友元類#
?注意:
? ? ? ? 1)友元提供了一種突破封裝的方式,有時提供了便利;
? ? ? ? 2)但是友元會增加耦合度,破壞了封裝,所以友元不宜多用。
????????通過定義友元函數,我們可以寫出邏輯正確的cout重載函數:
ostream& operator<<(ostream& out, const Date d)
{out << d._year << " " << d._month << " " << d._day;out << endl;return out;
}
?函數的效果:
?(三)內部類
? ? ? ? 什么是內部類?如果一個類,它定義在另一個類的內部,那么這個定義在內部的類就稱為“內部類”。
示例:
class A
{class B{int _c; };
};
此時,B就是A的內部類。?
內部類也是一個類,只不過他被A的作用域又封裝了一層,想要找到B,則要:
//創建一個類B,需要在A的作用域中去尋找A::B aa;
?內部類是一個獨立的類,它是外部類A的友元類:????????
? ? ? ? 內部類B可以訪問A的私有成員,而A不能訪問B的私有成員。
????????(內部可以訪問外部,而不能反著來)
?其他特性:
????????1. 內部類可以定義在外部類的public、protected、private都是可以的。
????????2. 注意內部類可以直接訪問外部類中的static成員,不需要外部類的對象/類名。
????????3. sizeof(外部類)=外部類,和內部類沒有任何關系。
(四)深入理解類和對象、總結
? ? ? ? 假如將來你要開一家外賣公司,需要打造你的項目,這時你該如何保存信息?
? ? ? ? 創建多個類:外賣騎手,商家,顧客類;
每個類包含的信息(包含的成員變量),擁有的功能(實現的函數)都是最必要的:
騎手:姓名,電話,實時位置信息等;
商家:店名,位置,菜品,價格信息等;
顧客:姓名,電話,住址信息等;
????????這些成員變量就是根據實際需求來定義的。對于這些類,他們之間也會有交互,需要實現交互函數,這就是后話了。
? ? ? ? 類和對象是一種能夠將現實生活中的關系相對較好的表現出來,這也是面向對象編程的實際需求。
? ? ? ? 與此同時,現實生活中的實體計算機并不認識現實生活中的對象,計算機只認識二進制格式的數據。如果想要讓計算機認識現實生活中的實體,用戶必須通過某種面向對象的語言,對實體進行描述,然后通過編寫程序,創建對象后計算機才可以認識。
考慮顯示需求:
? ? ? ? 對于商家,他們都有一個特征:他們是賣東西的,需要客戶。
? ? ? ? 對于騎手,他們的特征是:他們是接單送單的,需要商家的訂單。
? ? ? ? 對于顧客,他們的特征是:他們是需要產品的,要在商家那里消費的,需要商家。
????????據此,我們可以把所有的商家抽象為一類,創建一個商家類;把所有的騎手抽象為一個類,創建一個騎手類;把所有的顧客抽象為一個類,創建一個顧客類。
????????類是對象的抽象,對象是類的實際體現。
? ? ? ? 類的屬性和功能來源于生活中的實際需要。
?
用一張圖總結:
?
完~
未經作者同意禁止轉載?