前言
初始化列表是書寫構造函數的一種方式,某些成員變量之只能通過初始化列表進行初始化。另外學習c++不可避免地需要知道什么樣的變量存儲在什么區域當中如棧,堆,靜態區,常量區
初始化列表
書寫格式
書寫上,初始化列表,以冒號開始,以逗號分割的數據成員列表,每個成員變量后面個呢一個放在括號后面的初始值或表達式
如下圖所示給出一個日期類的初始化列表
class Date{
public:Date(int year = 1900,int month = 1,int day = 1):_year(year),_month(month),_day(day){}private:int _year;int _month;int _day;
};
初始化列表有什么作用
1.初始化列表可以代替大部分函數體內賦值
2.某些成員變量只能通過初始化列表初始化
引用成員變量,const成員變量,自定義類型變量(且該類沒有構造函數時)只能在初始化列表中初始化
一些需要注意的點
1.每個成員變量在初始化列表只能出現一次,不能重復定義
2.成員聲明的位置和初始化列表中變量的位置順序相同,因為初始化列表是根據成員定義時的位置一一初始化的
class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print(){cout<<_a1<<" "<<_a2<<endl;}
private:int _a2;int _a1;
}int main()
{A aa(1);aa.Print();
}
這個例子就能很好的體現上述問題,定義的順序和初始化列表的順序不同,所以a1在拷貝構造給a2時還沒有初始化,所以打印出來的應該是1和隨機值
3.初始化列表和函數體內賦值各有優略,比如函數體內賦值可以對malloc進行檢查等等
4.當我們使用初始化列表初始化自定義成員時,如果自定義成員的構造函數沒有缺省值,需要顯式傳參
靜態成員
區塊的分類
這里所說的分類都是虛擬內存,分為棧區,堆區,靜態區(數據段),代碼段(常量區)
靜態成員變量
靜態成員變量在類中聲明時,需要在最開頭加上static關鍵字,靜態成員變量不能夠在類內初始化,只能通過訪問限定符在類外初始化
靜態成員變量存放在靜態區
class Date{
public:Date(int year = 1900,int month = 1,int day = 1):_year(year),_month(month),_day(day){}static int sign;
private:int _year;int _month;int _day;};
int Date::sign = 1;
靜態成員變量依然收到private等關鍵字的限制,定義在public中可以用域限定符或者訪問操作符訪問
所有統一個類的對象共用一個靜態成員變量
不能用初始化列表來初始化靜態成員變量,定義只能在類外進行定義,使用域限定符
靜態成員函數
靜態成員函數和靜態成員變量很像,所有同一個類的對象共用,受private關鍵字限制
靜態成員函數沒有this指針,意味著它不能夠調用非靜態成員變量
我們一般喜歡使用靜態成員函數去調用靜態成員變量,配套使用
友元
友元有許多種,但是歸根結底友元的目的是讓私有的成員也能讓其他非成員的函數或者類訪問
比如
#include <iostream>
using namespace std;
class Date{
public:Date(int year = 1900,int month = 1,int day = 1):_year(year),_month(month),_day(day){}friend ostream& operator<<(ostream& out,Date& d);static int sign;
private:int _year;int _month;int _day;};
int Date::sign = 1;
ostream& operator<<(ostream& out,Date& d)
{out<<d._year<<" "<<d._month<<" "<<d._day;return out;
}int main()
{Date d1(2025,8,5);cout<<d1<<endl;cout<<d1.sign;
}
這樣一個流運算符的重載就只能寫成友元函數,因為他一定有一個ostream對象占用一個參數,而我們又希望他能夠輸出結果,那就只能使用友元了。
書寫的方法很簡單,只需要在類內聲明這個函數,并在最前方加上friend關鍵字即可
內部類天然是外部類的友元
類內可以定義內部類,內部類可以訪問外部類的所有成員,但是外部類無法訪問內部類的私有成員
注意:私有內部類受訪問限定符的限制