C++類與對象(下)

1.再談構造函數

在中篇裏,提到過構造函數,這裏提一下構造函數的一個重要的性質:初始化列表

class Date
{
public:
 Date(int year, int month, int day)
 {
 _year = year;
 _month = month;
 _day = day;
 }
 private:
 int _year,_month,_day;
 }

在C++中可以改造爲下面的代碼

class Date
{
public:
 Date(int year, int month, int day):_year(year),_month(month),_day(day)
 {
 }
 .......
 }

寫法爲構造函數名:賦值成員元素(形參),後跟函數體

Date(int year, int month, int day):_year(year),_month(month),_day(day)

初始化列表和缺省參數,以及函數內部對成員的賦值是可以共存的,
需要注意的以下幾點

  1. 初始化列表裏的變量不能重複

  2. 初始化只能初始一次

  3. 某些成員必須在初始化列表裏初始化—const成員變量 引用成員變量 自定義成員(沒有默認構造函數)

    儘量使用初始化列表初始成員,因爲不管你是否使用初始列表初始對 象,函數都會試圖先用初始列表初始。

小知識點:成員變量在類的聲明次序就是初始化列表的初始次序

class Array
{
public:
 Array(int size)
 :_size(size)
 , _array((int*)malloc(sizeof(int)*_size))
 {}
private:
 int* _array;
 int _size;
};

如果調用這段函數,就會發現系統給_array分配了一個非常大的空間,
這是因爲_size並沒有初始化是一個隨機值,但是編譯器根據_size的大小確定給_array的大小,這會導致空間的浪費。
防止的方法是,聲明的順序和定義的順序要一致
在代碼中除了可以這樣初始化對象Date d(2018)
還有一種情況是

Date d1(2018);
d1 = 201;

這裏需要知道匿名對象,所謂的匿名對象就是沒有名字的對象Date(2018)
普通的對象生命週期在函數的作用域內,但匿名對象的生命週期只在定義的那一行存在,即用即銷燬,它的作用主要是賦值

Date m=Date(2018);

上面的代碼

Date d1(2018);
 
 // 用一個整形變量給日期類型對象賦值
 ///實際編譯器背後會用2019構造一個無名對象,最後用無名對象給d1對象進行賦值
 d1 = 2019;

首先2019是int型,Date類的構造函數支持int型的傳參和隱式轉換有關

1.先用2019構造一個匿名對象。
2.再用匿名對象拷d1。
3.優化爲構造函數。

知識點:在C++98前只支持對單參數的類操作,而在C++11裏增加到了多參數`d1 = {2018,1,2};
在11年之前的編譯器不支持這種寫法。
用explicit修飾構造函數,將會禁止單參構造函數的隱式轉換。

2.static靜態

聲明爲static的類成員稱爲類的靜態成員,用static修飾的成員變量,稱之爲靜態成員變量;用static修飾,可以理解爲靜態成員是屬於某個類所有對象。所以不能再初始列表裏初始化。
生命週期和全局變量相同,初始化需要再類外初始化具體寫法爲
靜態的成員變量一定要在類外進行初始化。

變量類型 + 類名::變量名 = 賦值;

靜態成員變量的用處和C語言裏的全局變量類似,但是比全局變量更安全,有利於C++的封裝性。

成員函數,稱之爲靜態成員函數。
靜態成員函數只能調用靜態對象和非成員對象,原因是因爲靜態成員函數的參數沒有this傳參,
靜態的成員本身也是有private public protected的區別
小知識點C++11支持成員變量在定義時聲明直接初始化

class A
{
public:
.......
private:
 // 非靜態成員變量,可以在成員聲明時,直接初始化。;類似缺省函數
 int a = 10;
...
};

3.友元函數 友元類

所謂的友元可以理解爲朋友的關係,一個人和別人是朋友,可以偶爾在別人家裏玩,但是還不屬於這家人,這個規則在數據世界也成立
ostream<<(ostream& out,Date & d)
{.......
}

重載輸出操作符寫成這樣,但是我們會發現操作失敗,這是因爲重載完後是類的對象在左邊形參在右邊,

d1<<cout;

但是這與我們正常的習慣相反,所以我們可以把設置Date爲ostream的友元類,讓ostream可以訪問Date的私有成員
注意的的是,在一個類裏可以設置其他的類爲自己的友元類,使其他的類能夠訪問自己的私有成員可以寫成

friend &ostream operator<<(ostream out)
{
cout<<_year<<"-"<<_month<<"-"<<_day;
}

友元關係包括友元函數和友元類
友元類可以訪問和其有關係的類的private類成員,而自身不屬於被訪問的類,友元函數也有相同的性質,
提示:爲了C++的封裝性儘量少使用友元類和友元函數。

4.內部類

內部類就是一個類的內部又定義了一個類,類似下面的例子

class A
{
private:
 static int k;
 int h;
public:
 class B
 {
 public:
 void foo(const A& a)
 {
 cout << k << endl;//OK
 cout << a.h << endl;//OK
 }
 };
};

注意:
如果一個類定義在另一個類的內部,這個內部類就叫做內部類。注意此時這個內部類是一個獨立的
類,它不屬於外部類,更不能通過外部類的對象去調用內部類。外部類對內部類沒有任何優越的訪問權限。
注意:內部類就是外部類的友元類。注意友元類的定義,內部類可以通過外部類的對象參數來訪問外部類中
的所有成員。但是外部類不是內部類的友元。
如果用sizeof判斷大小不會將內部類的成員計算進來。
除此之外和普通的類沒什麼區別。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章