天天看點

類與對象_3

文章目錄

    • 構造函數
      • 初始化清單
      • 類型轉換
    • 靜态成員
    • 友元

構造函數

 首先讨論下什麼是構造函數*?

   它是建立對象時,給成員變量賦初始值的一個函數。

 通常情況下我們會這樣為變量賦初值:

//假設一個日期類
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
           

  但這裡并不是初始化,因為初始化隻能初始化一次,而在類體中可以多次為變量指派。

初始化清單

實作: :成員變量1(初始值:形參/表達式)

       ,成員變量2(初始值:形參/表達式)

       ...

  注意:

  1. 隻有構造函數才有成員變量初始化清單。在初始化期間會為各變量劃分空間。
  2. 初始化順序是根據聲明成員變量聲明的順序進行的,與其在初始化清單的順序無關。
  3. 盡量使用初始化清單初始化,因為不管你是否使用初始化清單,對于自定義類型成員變量,一定會先使用初始化清單初始化。

 可以在初始化清單進行初始化也可以在構造函數内進行初始化,那怎麼選擇?

   類類型成員(該類有非預設的構造函數),引用類型 和 const類型的變量初始化一定要放在初始化清單中初始化,因為它們都要求在定義

 時就要初始化。

 在有下面這種情況:Date類中建立Time類成員變量時,無法為其賦初始值,這就使得Time類的構造函數為全預設的構造函數 或者 Date類在其初始化清單的位置顯示調用并賦初始值給它。

類與對象_3

類型轉換

構造函數除了能夠建立對象和初始化對象外,還可以對單參的構造函數進行類型轉換。

  

類與對象_3

 這段代碼執行時會報錯,在這裡"d = 1997"會進行隐式轉換。

   

類與對象_3

因為單參構造函數,全預設構造函數都可以被調用是以系統不知道調用那個,就會報錯。

 解決上述問題的方式,就是在單參構造函數聲明前加"explicit"

  關鍵字: explicit

   作用:禁止單參的構造函數類型隐式轉化。

靜态成員

 在c++類中聲明成員時可以加上static關鍵字,這樣聲明的成員就叫做靜态成員。

特性:

  1. 靜态成員變量必須在類外進行顯式初始化,定義時不添加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;   // 類外初始化靜态變量
           
  1. 靜态成員為所有類對象所共享,即使沒有對象建立,類的靜态資料成員也存在;
  2. 從外部通路類的靜态成員通過"類名 :: 靜态成員",“對象 . 靜态成員” 或者 指針 來通路;
int main()
{
	cout << Date::PrintYear() << endl;  // 類名直接通路
	Date d1;
	Date* d2;
	int tmp = d1.PrintYear();   // 對象.引用的方式
	int tmp2 = d2->PrintYear(); // 指針方式

	return 0;
}
           
  1. 靜态成員函數沒有隐藏的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;
}
           
  1. 靜态成員和類的普通成員一樣,也有public、protected、private3種通路級别,也可以具有傳回值,const修飾符等參數;
  2. 由于靜态成員是在靜态存儲區,而不是堆棧區建立的,是以靜态成員變量在對象中不占記憶體。

友元

 友元函數 & 友元類

  優缺點:友元提供了一種突破封裝的方式,有時提供了便利。但是友元會增加耦合度,破壞了封裝,是以友元不宜多用。

 友元函數

   假如我們重載輸出操作符"<<",如果放在類内當作一個成員函數,由于類的成員函數第一個參數一定是隐含的this指針,是以我們調用方式一定是使用Date類的對象(this指針),然而這樣的輸出語句不符合我們習慣常用的。為此我們就需要在類外定義一個具有全局屬性的operator函數,但這樣又沒辦法使用類中的私有成員變量,此時就可以借助友元函數的方式解決。

類與對象_3

  用法: 友元函數可以在類内任何位置聲明(别在定義成員變量那就行),并且要在聲明前加 “friend”,它的定義放在類外與普通函數方式一樣。

     這樣友元函數就可以直接通路類的私有成員變量。

 總結:

  1. 友元函數可通路類的私有成員,但不是類的成員函數; // 子類也就不能繼承基類的友元函數
  2. 友元函數不能用const修飾 ;   // 因為聲明中const修飾的是實際是this指針,而友元函數不屬于類函數,是以沒有this指針,也就不能被const修飾
  3. 友元函數可以在類定義的任何地方聲明,不受類通路限定符限制;
  4. 一個函數可以是多個類的友元函數;
  5. 友元函數的調用與普通函數的調用原理相同;
  6. 友元關系是單向的,不具有交換性,不能傳遞;
c++

繼續閱讀