? ? ? ? 今天又重新回到c++的學習中~在前兩篇博客中,我簡單的學習了類的定義,實例化,以及類中的默認成員函數.下篇是類和對象的收尾篇,在這篇中我將補充一下中篇所講的構造函數以及介紹一些類和對象的新知識.下面讓我們開始學習吧.
再談構造函數
? ? ? ? 在之前我們實現構造函數時,初始化成員變量主要用函數體內的賦值,但是構造函數還可以用初始化列表進行成員變量的初始化,(并且最好以后都用初始化列表).初始化列表使用方式為以一個冒號開始,以逗號分隔的數據成員列表,每個成員變量后跟一個放在括號中的初始值或表達式(可以寫在一行,但推薦每個成員獨占一行).
? ? ? ? 每個成員變量在初始化列表中只能出現一次,初始化列表是每個成員變量定義初始化的地方.
? ? ? ? 引用成員變量,const修飾的成員變量,沒有默認構造的類類型變量必須在初始化列表處進行初始化,否則會編譯報錯.
????????c++11支持在成員變量的聲明處給缺省值.這個初始值會給到初始化列表,用于給沒有在初始化列表中顯示初始化的成員初始化.如果在初始化列表中顯示初始化了缺省值就沒用了.
????????盡量使?初始化列表初始化,因為那些你不在初始化列表初始化的成員也會?初始化列表,如果這個成員在聲明位置給了缺省值,初始化列表會?這個缺省值初始化。如果你沒有給缺值,對于沒有顯?在初始化列表初始化的內置類型成員是否初始化取決于編譯器,C++并沒有規定。對于沒有顯?在初始化列表初始化的自定義類型成員會調用這個成員類型的默認構造函數,如果沒有默認構造會編譯錯誤。
????????初始化列表中按照成員變量在類中聲明順序進行初始化,跟成員在初始化列表出現的的先后順序?關。(建議類的成員變量的聲明順序和初始化列表順序保持?致).
? ? ? ? 注:?論是否顯?寫初始化列表,每個構造函數都有初始化列表.
? ? ? ? ? ? ??論是否在初始化列表顯示初始化成員變量,每個成員變量都要?初始化列表初始化.
? ? ? ? 下表為上面內容的大體總結:
? ? ? ? 下面為一些對應代碼:
//簡單的實驗初始化列表
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;class Date
{
public://錯誤示范//Date(int year , int month , int day )// :_year(2025)// , _month(3)// , _day(13)//{////}//正確做法Date(int year=2025, int month=3, int day=13):_year(year),_month(month),_day(day){}void Print(){cout << _year << " " << _month << " " << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{//錯誤示范對應的測試//Date d1;//會報錯,不要將初始畫列表與函數的缺省值弄混了//這里沒有缺省值,必須要寫實參,如下//Date d1(2222, 2, 2);//d1.Print();//調用之后發現無論給什么值去初始化最后都會打印初始化列表對應的日期Date d1;d1.Print();Date d2(2024,3,14);d2.Print();return 0;
}
class Time
{
public:Time(int hour):_hour(hour){cout << "Time(int hour)" << endl;}
private:int _hour;
};
class Date
{
public:Date(int year = 2025, int month = 3, int day = 13):_year(year), _month(month), _day(day),_a(_day),_b((int*)malloc(sizeof(int)*4))//可以用表達式來初始化, _t1(10){//錯誤示范// 引用成員變量,const修飾的成員變量,沒有默認構造的類類型變量// 必須在初始化列表處進行初始化,否則會編譯報錯.//a = _day;//b = 2;//t1(1);}void Print(){cout << _year << " " << _month << " " << _day << endl;cout << _a << " " << _b << " " << endl;}
private:int _year;int _month;int _day;int& _a;const int* _b;Time _t1;
};
// class Time
//{
//public:
// Time(int hour)
// :_hour(hour)
// {
// cout << "Time(int hour)" << endl;
// }
//private:
// int _hour;
//};
//class Date
//{
//public:
// Date(int year = 2025, int month = 3, int day = 13)
// :_a(_day)
// , _b((int*)malloc(sizeof(int) * 4))//可以用表達式來初始化
// , _t1(10)
// {
// _year = year;
// _month = month;
// _day = day;
// //也可以混著用
// }
// void Print()
// {
// cout << _year << " " << _month << " " << _day << endl;
// cout << _a << " " << _b << " " << endl;
// }
//private:
// int _year;
// int _month;
// int _day;
//
// int& _a;
// const int* _b;
// Time _t1;
//};int main()
{Date d1;d1.Print();return 0;
}
class Date
{
public:Date(int year = 2025, int month = 3, int day = 13){}void Print(){cout << _year << " " << _month << " " << _day << endl;}
private://可以在聲明時給缺省值,作用在初始化列表上int _year=2024;int _month=5;int _day=21;
};int main()
{Date d1;d1.Print();return 0;
? ? ? ? 上面這個程序輸出見上.因為_a1,_a2在初始化列表上都顯示初始化了,所以下面的缺省值就沒有用了.又因為初始化列表中按照成員變量在類中聲明順序進行初始化,所以輸出值為1,隨機值.
類型轉換
? ? ? ? c++支持內置類型隱式轉化為類類型的對象,但需要有相關內置類型為參數的構造函數.
????????構造函數前?加explicit就不再?持隱式類型轉換.
????????類類型的對象之間也可以隱式轉換,需要相應的構造函數?持.
? ? ? ? 下面為一些代碼:
class A
{
public://explicit A(int a = 1)// :_a1(a)//{// cout << "A(int a)" << endl;//}//加了explicit之后就禁止隱式轉換了A(int a = 1):_a1(a){cout << "A(int a)" << endl;}A(int a, int b):_a1(a), _a2(b){cout << "A(int a, int b)" << endl;}int Geta1()const//因為下面為只讀引用,所以這里要加const修飾*this{return _a1;}
private:int _a1 = 1;int _a2 = 1;
};class B
{
public:B(const A& a)//這里用const修飾了,a就只讀了所以*this也要只讀(205行):_b(a.Geta1()){cout << "B(const A& a)" << endl;}
private:int _b = 1;
};int main()
{A aa1 = 2;//隱式類型轉換+拷貝構造A aa2 = { 3,4 };//隱式類型轉換+拷貝構造B bb = aa1;//隱式類型轉換+拷貝構造return 0;
}
static成員
?????????static修飾的成員變量,稱之為靜態成員變量,靜態成員變量?定要在類外進行初始化.靜態成員變量為所有類對象所共享,不屬于某個具體的對象,不存在對象中,存放在靜態區.?
????????靜態成員變量不能在聲明位置給缺省值初始化,因為缺省值是個構造函數初始化列表的,靜態成員變量不屬于某個對象,不走構造函數初始化列表.靜態成員變量第一次創建(在內存中開空間)是在他第一次使用的時候.
?????????static修飾的成員函數,稱之為靜態成員函數,靜態成員函數沒有this指針.靜態成員函數中可以訪問其他的靜態成員,但是不能訪問類中非靜態的,因為沒有this指針(靜態成員函數一般用于取得靜態成員變量).但是非靜態的成員函數,可以訪問任意的靜態成員變量和靜態成員函數.
????????突破類域就可以訪問靜態成員,可以通過類名::靜態成員或者對象.靜態成員來訪問靜態成員變量 和靜態成員函數.(在全局中可以通過上兩種方式來初始化私有的靜態成員變量).靜態成員也是類的成員,受public、protected、private 訪問限定符的限制.(若在類中設置成私有那么就不可以在main函數中突破類域直接訪問).
練習:實現?個類,計算程序中創建出了多少個類對象?
class A
{
public:A(int n = 0):_aa(n){++_a;}//~A()//{// --_a;//}static int Get_a(){return _a;}
private:int _aa;static int _a;
};int A::_a = 0;
void func()
{A a4;
}
int main()
{A a1;A a2;A a3;func();cout << a1.Get_a() << endl;cout << A::Get_a() << endl;//也可以通過類來調用靜態成員變量return 0;
}
? ? ? ? 好啦,今天的學習就到這里啦,在下一篇博客會把類和對象的最后一點東西寫完,那我們下篇博客見.晚安~