类成员函数解析
?
1、? 構造函數:
(1)??????定義:是一個特殊的成員函數,名字與類名相同,創建類類型對象時,由編譯器自動調用,在對象的生命周期內只且只調用一次,以保證每個數據成員都有一個合適的初始值。
(2)??????特性:
1、函數名與類名相同。
2、沒有返回值。
3、有初始化列表(可以不用)。
4、新對象被創建,由編譯器自動調用,且在對象的生命期內僅調用一次。
5、構造函數可以重載,實參決定了調用那個構造函數。
6、如果沒有顯式定義時,編譯器會提供一個默認的構造函數。
7、無參構造函數和帶有缺省值得構造函數都認為是缺省構造函數,并且缺省構造函數只能有一個。
(3)分類:
?
無參構造函數:如果沒有顯式的定義一個構造函數,系統將默認合成一個無參構造函數,參數為空,什么都不做。
?
顯式的定義一個無參構造函數,如下例:
??? Time()
??? {
?????? cout<<"Time(int intint )"<<endl;
??? }
?
普通構造函數(也稱重載構造函數):
class Time
{
public:
??? Time(int h, int m, int s)
??? {
?????? _hour = h;
?????? _minute = m;
?????? _second = s;
?????? cout<<”Time(int, int, int)”<<endl;
??? }
private:
??? int _hour;
??? int _minute;
??? int _second;
};
?
?
系統默認合成的構造函數:在A類有缺省的構造函數,B類沒有顯示的定義構造函數,B類中含有A類類型成員,此時系統默認合成構造函數。
class Time
{
public:
?
??? Time()
??? {
?????? cout<<"Time(int intint )"<<endl;
??? }
private:
??? int _hour;
??? int _minute;
??? int _second;
};
class Date
{
private:
??? int _year;
??? int _month;
??? int _day;
??? Time t;
?
};
?
?
運行結果:
?
?
?
?
初始化列表:
以一個冒號開始,接著是一個以逗號分隔的數據成員列表,每個數據成員后面跟一個放在園括號中的初始化式。
classDate
{
public:
??? ?Date(int year = 1, int month = 2, int day = 3)
?????? :_year(year),
?????? _month(month),
?????? _day(day)
?????? {
?????????? cout<<"Date(int, int, int)"<<endl;
?????? }
private:
??? int _year;
??? int _month;
??? int _day;
?
};
初始化順序:
?
1、初始化列表僅用于初始化數據成員,并不指定這些數據成員的初始化順序,數據成員在類中定義順序就是在參數列表中的初始化順序。
?
2、每個成員在初始化列表中只能出現一次,盡量避免使用成員初始化成員,成員的初始化順序最好和成員的定義順序保持一致。
?
類中包含以下成員必須要放在初始化列表中初始化:
class Time
{
public:
??? //Time()
??? //{}
??? Time(int h, int m, int s)
??? {
?????? cout<<"Time(int intint )"<<endl;
??? }
private:
??? int _hour;
??? int _minute;
??? int _second;
};
?
class Date
{
public:
??? ?Date(int year, int month, int day)
?????? :_year(year),
?????? _month(month),
?????? _day(day),
?????? t(0, 0, 0)
?????? {
?????????? cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
?????? }
private:
??? int _year;
??? int _month;
??? int _day;
??? const int a;
??? int& b;
};
1、引用數據成員
2、const數據成員
?
?
3、類類型成員(該類沒有缺省的構造函數):Time類中沒有缺省的構造函數(無參構造函數,有參數,但有缺省的構造函數),要調用Date類創建對象,則類內的成員都要初始化,Date類中含有Time類類型成員,只能在初始化列表內進行初始化
?
?
?
?
?
?
2、? 拷貝構造函數
顯式的定義拷貝構造函數:
class Date
{
public:
??? ?Date(int year = 1, int month = 2, int day = 3)
?????? :_year(year),
?????? _month(month),
?????? _day(day)
?????? {
?????????? cout<<"Date(int, int,int)"<<endl;
?????? }
??? ?Date(const Date &d)
?????? :_year(d._year),
?????? _month(d._month),
?????? _day(d._day)
??? ?{
?????? cout<<"Date(&d)"<<endl;
??? ?}
?
private:
??? int _year;
??? int _month;
??? int _day;
};
void FunTest()
{
??? Date d;
??? Date d1(d);
}
運行結果:
?????? 系統默認合成拷貝構造函數:在A類有缺省的構造函數,B類沒有顯示的定義拷貝構造函數,B類中含有A類類型成員,此時系統默認合成拷貝構造函數。
class Time
{
public:
?
??? Time()
??? {
?????? cout<<"Time(int intint )"<<endl;
??? }
private:
??? int _hour;
??? int _minute;
??? int _second;
};
class Date
{
public:
??? ?Date(int year = 1, int month = 2, int day = 3)
?????? :_year(year),
?????? _month(month),
?????? _day(day)
?????? {
?????????? cout<<"Date(int, int,int)"<<endl;
?????? }
?
private:
??? int _year;
??? int _month;
??? int _day;
??? Time t;
};
void FunTest()
{
??? Date d;
??? Date d1(d);
}
運行結果:
?
3、? 析構函數:與構造函數功能相反,在對象被銷毀時,由編譯器自動調用,完成類的一些資源清理和汕尾工作
?
析構函數特性:
a、析構函數在類名(即構造函數名)加上字符~。
b、析構函數無參數無返回值。
c、一個類有且只有一個析構函數。若未顯示定義,系統會自動生成缺省的析構函數。
d、對象生命周期結束時,C++編譯系統系統自動調用析構函數。
e、注意析構函數體內并不是刪除對象,而是做一些清理工作
?
class Date
{
public:
??? Date(int year, int month, int day)
?????? : _year(year)
?????? , _month(month)
?????? , _day(day)
??? {
?????? cout<<"Date(int, int,int):"<<this<<endl;
??? }
?
??? Date(const Date& d)
?????? : _year(d._year)
?????? , _month(d._month)
?????? , _day(d._day)
??? {
?????? cout<<"Date(constDate& d):"<<this<<endl;
??? }
?
??? Date& operator=(const Date& d)
??? {
?????? cout<<"Date&operator=(const Date& d):"<<this<<endl;
?????? if (this != &d)
?????? {
?????????? _year = d._year;
?????????? _month = d._month;
?????????? _day = d._day;
?????? }
?
?????? return *this;
??? }
?
??? ~Date()
??? {
?????? cout<<"~Date():"<<this<<endl;
??? }
?
private:
??? int _year;
??? int _month;
??? int _day;
};
?
void FunTest()
{
??? Date d(2016, 10, 17);
??? Date d1(d);
}
運行結果:
析構函數銷毀對象原則:先構造后析構,后構造先析構。
?
賦值運算符重載:
?
????? 在面向對象程序設計中,對象間的相互拷貝和賦值是經常進行的操作,如果對象在申明的同時馬上進行的初始化操作,則稱之為拷貝運算。例如:
???????class?A(“Date”) ;? class B = A;
?????此時其實際調用的是B(A)這樣的淺拷貝操作。
????如果對象在申明之后,在進行的賦值運算,我們稱之為賦值運算。例如:
????????class? A("Date");? class B;
????????B=A;
????????此時實際調用的類的缺省賦值函數B.operator=(A);
?
class Date
{
public:
??? Date(int year = 2016, int month = 10 , int day = 1)
?????? : _year(year)
?????? , _month(month)
?????? , _day(day)
??? {
?????? cout<<"Date(int, int,int):"<<this<<endl;
??? }
?
??? Date(const Date& d)
?????? : _year(d._year)
?????? , _month(d._month)
?????? , _day(d._day)
??? {
?????? cout<<"Date(constDate& d):"<<this<<endl;
??? }
?
??? Date& operator=(const Date& d)
??? {
?????? cout<<"Date&operator=(const Date& d):"<<this<<endl;
?????? if (this != &d)
?????? {
?????????? _year = d._year;
?????????? _month = d._month;
?????????? _day = d._day;
?????? }
?????? return *this;
??? }
?
??? ~Date()
??? {
?????? cout<<"~Date():"<<this<<endl;
??? }
?
private:
??? int _year;
??? int _month;
??? int _day;
};
void FunTest()
{
??? Date d(2016, 10, 17);
Date d1(d); // 調用拷貝構造函數進行拷貝
Date d2;
??? D2 = d;????//d1.operator(&d)賦值運算符重載
}
程序編譯之后,d1 和 d2 在棧上都分配了內存,,對象d1 的域被初始化,d2為隨機值。
如果我們簡單的執行Date d1(d); 即 Date d1 = d; 則其執行的是缺省定義的缺省的賦值運算。所謂缺省的賦值運算,是指對象中的所有位于stack中的域,進行相應的復制。但是,如果對象有位于heap上的域的話,其不會為拷貝對象分配heap上的空間,而只是指向相同的heap上的同一個地址。
因此,對于缺省的賦值運算,如果對象域內沒有heap上的空間,其不會產生任何問題。但是,如果對象域內需要申請heap上的空間,那么在析構對象的時候,就會連續兩次釋放heap上的同一塊內存區域,從而導致異常。
?
故需要用賦值運算符重載
?
Date d2;
??? D2 = d;????//d1.operator(&d)賦值運算符重載
?
? Date& operator=(const Date& d)
??? {
?????? cout<<"Date&operator=(const Date& d):"<<this<<endl;
??? ??? if (this != &d)
?????? {
?????????? _year = d._year;
?????????? _month = d._month;
?????????? _day = d._day;
?????? }
?????? return *this;
? }//一定要返回引用,否則返回其值后立即消失,不能連續賦值
?
總結
- 上一篇: java打印的globa类l_Sprin
- 下一篇: 【无标题】计算机一级考试MS OFFIC