類和物件中
- 一、 類的6個默認成員函式
- 二、 建構式
- 三.、解構式
- 四、 拷貝建構式
- 五、 賦值運算子多載
- 六、 const成員函式
- 七、 取地址及const取地址運算子多載
一、 類的6個默認成員函式
默認成員函式,簡單來說,就是如果我們不在編譯器里進行寫入,那編譯器會自動生成默認成員函式,如果寫了,就用自己寫的,
附:有些編譯器默認生成不可用,需要自己寫,
有些編譯器生成可用,不需要寫,

二、 建構式
1.建構式的概念:建構式是一個特殊的成員函式,名字與類名相同,創建型別別物件時由編譯器自動呼叫,保證每個資料成員都有 一個合適的初始值,并且在物件的生命周期內只呼叫一次,
建構式并不是構造一個物件,而指的是去初始化這個物件,
2.建構式的四個特性:
(1)函式名與類名相同
(2)沒有回傳值
(3)物件實體化時編譯器自動呼叫對應的建構式

(4)建構式可以多載

(5) 如果類中沒有顯式定義建構式,則C++編譯器會自動生成一個無參的默認建構式,如果用戶顯式定義編譯器將不再生成,
class Date
{
public:
/*
// 如果用戶顯式定義了建構式,編譯器將不再生成
Date (int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
*/
private:
int _year;
int _month;
int _day;
};
void Test()
{
// 沒有定義建構式,物件也可以創建成功,因此此處呼叫的是編譯器生成的默認建構式
Date d;
}
(6) 無參的建構式和全預設的建構式都稱為默認建構式,并且默認建構式只能有一個,
無參建構式、全預設建構式、編譯器默認生成的建構式,都可以當成默認成員函式,
class Stack
{
public:
Stack(int capacity = 4)
{
_a =(int*) malloc(sizeof(int)* capacity);
_size = 0;
_capacity = capacity;
}
private:
int _size;
int _capacity;
int* _a;
};
int main()
{
Stack St1;
Stack St2(10);
}
(7)Date() 和 Date (int year = 1900, int month = 1, int day = 1) 不能同時存在
如果兩者同時存在,那么下方代碼d2的構造,初始化會存在歧義,
class Date
{
public:
Date()
{
_year = 1900 ;
_month = 1 ;
_day = 1;
}
Date (int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
private :
int _year ;
int _month ;
int _day ;
};
// 以下測驗函式能通過編譯嗎?
void Test()
{
Date d1(2000,1,1);
Date d2;
}
(8)成員變數中的兩種型別:基本型別(內置型別)和自定義型別
在沒有寫建構式的情況下,編譯器會自動生成默認建構式:
對于成員變數中的基本型別,建構式不做任何事情,
對于成員變數中的自定義型別,它會去呼叫自己的默認建構式必須為 (不傳引數的建構式)
class Date
{
private:
// 基本型別(內置型別)
int _year;
int _month;
int _day;
// 自定義型別
Time _t;
};
int main()
{
Date d;
return 0; }
三.、解構式
**1.解構式的概念:**物件在銷毀時會呼叫解構式,完成類的資源清理作業,
2.解構式的特性:
- 解構式名是在類名前加上字符 ~,
- 無引數無回傳值,
- 一個類有且只有一個解構式,若未顯式定義,系統會自動生成默認的解構式,
- 物件生命周期結束時,C++編譯系統系統自動呼叫解構式,
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//解構式
~Date()
{
//日期類沒有需要清理的資源,嚴格來說,Date不需要寫解構式
//系統自動默認生成
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
class Stack
{
public:
Stack(int capacity=4)
{
cout << "hello" << endl;
_a = (int*)malloc(sizeof(int)* capacity);
_size = 0;
_capacity = capacity;
}
//日期類沒有資源要清理,不需要自己寫解構式
//而像Stack這種類,要清理釋放資源,一定要自己實作解構式
//Stack的解構式
~Stack()
{
cout <<"hello" << endl;
free(_a);
_a = nullptr;
_size = 0;
_capacity = 0;
}
private:
int _size;
int _capacity;
int *_a;
};
int main()
{
Date d1;
Stack T1;
}
3.默認解構式,會針對成員變數中自定義型別String _name來處理,呼叫它的解構式,而對于內置型別不進行處理,
注:此處解構式跟建構式相類似,
class String
{
public:
String(const char* str = "jack")
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
//解構式
~String()
{
cout << "~String()" << endl;
free(_str);
}
private:
char* _str;
};
class Person
{
private:
//自定義型別
String _name;
//基本型別(內置型別)
int _age;
};
int main()
{
Person p;
return 0;
四、 拷貝建構式
1.建構式:只有單個形參,該形參是對本型別別物件的參考(一般常用const修飾),在用已存在的型別別物件創建新物件時由編譯器自動呼叫,
2.特性:
1.拷貝建構式是建構式的一個多載形式,
2. 拷貝建構式的引數只有一個且必須使用參考傳參,使用傳值方式會引發無窮遞回呼叫,
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
//const可以避免在賦值時寫反,避免錯誤
{
_year = d._year;
_month = d._month;
_day = d._day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
return 0;
}
如果不使用參考傳參,則會引發無窮遞回,而使用參考傳參,呼叫拷貝建構式需要傳參,形參是實參的別名,就直接進入了,

void f(Date d)
{
}
int main()
{
Date d1;
d1.print();
Date d2(d1);
d2.print();
//自定義型別的傳值傳參,不僅僅是把物件空間的值拷貝過來
//必須要呼叫拷貝建構式來完成,否則會有深淺拷貝的問題
f(d2);
return 0;
}
3.若未顯示定義,系統生成默認的拷貝建構式, 默認的拷貝建構式物件按記憶體存盤按位元組序完成拷貝,這種拷貝我們叫做淺拷貝,或者值拷貝,
對于日期類這種拷貝,叫做淺拷貝,
對于Stack這樣關注著記憶體塊資源的類,需要自己實作拷貝構造,搞成深拷貝,
五、 賦值運算子多載
1.運算子多載概念:運算子多載是具有特殊函式名的函式,也具有其回傳值型別,函式名字以及引數串列,其回傳值型別與引數串列與普通的函式類似,
(自定義型別可以像內置型別使用運算子)自定義型別在默認情況下是不能使用運算子的,
如果要使用,那么就需要多載運算子,
函式名字為:關鍵字operator后面接需要多載的運算子符號,
函式原型:回傳值型別 operator運算子(引數串列)
2.注意:
1.不能通過連接其他符號來創建新的運算子:比如operator@
2.多載運算子必須有一個型別別或者列舉型別的運算元
3.用于內置型別的運算子,其含義不能改變,例如:內置的整型+,不能改變其含義
作為類成員的多載函式時,其形參看起來比運算元數目少1成員函式的運算子有一個默認的形參this,限定為第一個形參
4…* 、:: 、sizeof 、?: 、. 注意以上5個運算子不能多載,這個經常在筆試選擇題中出現,
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//private:
int _year;
int _month;
int _day;
};
//定義全域的 operator==
// 這里會發現運算子多載成全域的就需要成員變數是共有的,那么問題來了,封裝性如何保證?
// 這里其實可以用我們后面學習的友元解決,或者干脆多載成成員函式,
bool operator==(Date d1, Date d2)
{
return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}
int main()
{
Date d1;
d1.print();
Date d2(d1);
d2.print();
operator==(d1, d2);
d1 == d2;
return 0;
}
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//d1 = d2;->d1.operator(d2);->d1.operator(&d1,d2)
bool operator==(const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
//private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.print();
Date d2(d1);
d2.print();
d1.operator==(d2);
d1==d2;
return 0;
}
3.賦值運算子的多載:
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//完整的賦值運算子多載
Date& operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.print();
Date d2(d1);
d2.print();
/*d1.operator==(d2);
d1==d2;
return 0;*/
Date d3(2021, 4, 17);
//d2 = d3;
//d1 = d2;
d1 =d2 = d3;
d1.print();
return 0;
}
賦值運算子多載的特點:
- 引數型別
- 回傳值
- 檢測是否自己給自己賦值
- 回傳*this
- 一個類如果沒有顯式定義賦值運算子多載,編譯器也會生成一個,完成物件按位元組序的值拷貝,
**總結:**operator=跟構造拷貝類似,我們不實作,編譯器會默認生成,operator=,會完成按位元組的值拷貝(淺拷貝),
對于Date(日期類),默認生成的構造拷貝和operator=都可以用,不需要去寫,
對于Stack這樣的類,默認生成的構造拷貝和operator=為淺拷貝都不能用,需要我們自己實作深拷貝,
六、 const成員函式
1.const修飾類的成員函式:將const修飾的類成員函式稱之為const成員函式,const修飾類成員函式,實際修飾該成員函式隱含的this指標,表明在該成員函式中不能對類的任何成員進行修改,

2.小結論:
- const物件不可以呼叫非const成員函式
- 非const物件可以呼叫const成員函式
- const成員函式內不可以呼叫其它的非const成員函式
- 非const成員函式內可以呼叫其它的const成員函式
- 能否呼叫主要看this指標能否傳過去,能否傳遞,主要看的是權限的縮小(ok)還是放大(no)
七、 取地址及const取地址運算子多載
class Date
{
public :
//如果假設想讓非const物件取地址,可以return nullptr;
//不return *this;
Date* operator&() //普通物件取地址多載
{
return this ;
}
const Date* operator&()const //const取地址多載
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
這兩個運算子一般不需要多載,使用編譯器生成的默認取地址的多載即可,只有特殊情況,才需要多載,比如想讓別人獲取到指定的內容,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/278523.html
標籤:區塊鏈
上一篇:Golang開發--結構體的使用
下一篇:C#基礎06(基礎的增刪改查)
