文章目錄
-
- 構造函數
-
- 初始化清單
- 類型轉換
- 靜态成員
- 友元
構造函數
首先讨論下什麼是構造函數*?
它是建立對象時,給成員變量賦初始值的一個函數。
通常情況下我們會這樣為變量賦初值:
//假設一個日期類
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
但這裡并不是初始化,因為初始化隻能初始化一次,而在類體中可以多次為變量指派。
初始化清單
實作: :成員變量1(初始值:形參/表達式)
,成員變量2(初始值:形參/表達式)
...
注意:
- 隻有構造函數才有成員變量初始化清單。在初始化期間會為各變量劃分空間。
- 初始化順序是根據聲明成員變量聲明的順序進行的,與其在初始化清單的順序無關。
- 盡量使用初始化清單初始化,因為不管你是否使用初始化清單,對于自定義類型成員變量,一定會先使用初始化清單初始化。
可以在初始化清單進行初始化也可以在構造函數内進行初始化,那怎麼選擇?
類類型成員(該類有非預設的構造函數),引用類型 和 const類型的變量初始化一定要放在初始化清單中初始化,因為它們都要求在定義
時就要初始化。
在有下面這種情況:Date類中建立Time類成員變量時,無法為其賦初始值,這就使得Time類的構造函數為全預設的構造函數 或者 Date類在其初始化清單的位置顯示調用并賦初始值給它。
類型轉換
構造函數除了能夠建立對象和初始化對象外,還可以對單參的構造函數進行類型轉換。
這段代碼執行時會報錯,在這裡"d = 1997"會進行隐式轉換。
因為單參構造函數,全預設構造函數都可以被調用是以系統不知道調用那個,就會報錯。
解決上述問題的方式,就是在單參構造函數聲明前加"explicit"
關鍵字: explicit
作用:禁止單參的構造函數類型隐式轉化。
靜态成員
在c++類中聲明成員時可以加上static關鍵字,這樣聲明的成員就叫做靜态成員。
特性:
- 靜态成員變量必須在類外進行顯式初始化,定義時不添加static關鍵字;
class Date{
public:
Date(int year = 2018, int month = 10, int day = 12)
:_month(month)
,_day(day)
{}
private:
static int _year; // 聲明 "_year" 為靜态變量
int _month;
int _day;
};
int Date::_year = 2018; // 類外初始化靜态變量
- 靜态成員為所有類對象所共享,即使沒有對象建立,類的靜态資料成員也存在;
- 從外部通路類的靜态成員通過"類名 :: 靜态成員",“對象 . 靜态成員” 或者 指針 來通路;
int main()
{
cout << Date::PrintYear() << endl; // 類名直接通路
Date d1;
Date* d2;
int tmp = d1.PrintYear(); // 對象.引用的方式
int tmp2 = d2->PrintYear(); // 指針方式
return 0;
}
- 靜态成員函數沒有隐藏的this指針,不能直接通路任何非靜态成員,但是可以通過對象名間接的通路;
class Date{
public:
Date(int year = 2018, int month = 10, int day = 12)
:_month(month)
,_day(day)
{}
static void Print(const Date &d) // 通過引用已建立好的對象來通路其他非靜态成員變量
{
int year = _year;
//int month = _month; // 由于靜态函數沒有this指針,
//int day = _day; // 就無法直接通路非靜态成員變量
int month = d._month;
int day = d._day;
cout << year << "-" << month << "-" << day << endl;
}
private:
static int _year;
int _month;
int _day;
};
int Date::_year = 2018;
int main()
{
Date d1;
Date::Print(d1);
return 0;
}
- 靜态成員和類的普通成員一樣,也有public、protected、private3種通路級别,也可以具有傳回值,const修飾符等參數;
- 由于靜态成員是在靜态存儲區,而不是堆棧區建立的,是以靜态成員變量在對象中不占記憶體。
友元
友元函數 & 友元類
優缺點:友元提供了一種突破封裝的方式,有時提供了便利。但是友元會增加耦合度,破壞了封裝,是以友元不宜多用。
友元函數
假如我們重載輸出操作符"<<",如果放在類内當作一個成員函數,由于類的成員函數第一個參數一定是隐含的this指針,是以我們調用方式一定是使用Date類的對象(this指針),然而這樣的輸出語句不符合我們習慣常用的。為此我們就需要在類外定義一個具有全局屬性的operator函數,但這樣又沒辦法使用類中的私有成員變量,此時就可以借助友元函數的方式解決。
用法: 友元函數可以在類内任何位置聲明(别在定義成員變量那就行),并且要在聲明前加 “friend”,它的定義放在類外與普通函數方式一樣。
這樣友元函數就可以直接通路類的私有成員變量。
總結:
- 友元函數可通路類的私有成員,但不是類的成員函數; // 子類也就不能繼承基類的友元函數
- 友元函數不能用const修飾 ; // 因為聲明中const修飾的是實際是this指針,而友元函數不屬于類函數,是以沒有this指針,也就不能被const修飾
- 友元函數可以在類定義的任何地方聲明,不受類通路限定符限制;
- 一個函數可以是多個類的友元函數;
- 友元函數的調用與普通函數的調用原理相同;
- 友元關系是單向的,不具有交換性,不能傳遞;