W...Y的主頁 ??
代碼倉庫分享???
??前言:
前一篇博客中我們已經了解并學習了初始化和清理模塊中的構造函數與析構函數,還有拷貝復制中的拷貝復制函數,它們都是類與對象中重要的成員,今天我們要來講一下拷貝復制模塊中另一個非常重要的內容——賦值重載,但是在學習賦值重載的同時我們應該先學習運算符重載,話不多說我們直接開始!
目錄
賦值運算符重載
運算符重載
?賦值運算符重載
賦值運算符重載
運算符重載
C++為了增強代碼的可讀性引入了運算符重載,運算符重載是具有特殊函數名的函數,也具有其
返回值類型,函數名字以及參數列表,其返回值類型與參數列表與普通的函數類似。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// Date(const Date& d) ?// 正確寫法
void print()
{
cout << _year << '/' << _month << '/' << _day << endl;
}
Date(const Date& d) ?// 錯誤寫法:編譯報錯,會引發(fā)無窮遞歸
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(2022,10,23);
int x = 1;
int y = 2;
bool ret = x > y;
return 0;
}
?上圖是比較的反匯編代碼,我們可以看出編譯器可以直接做出運算符判斷。
一般情況下,我們去比較內置類型都非常容易去比較,因為內置類型都是一些基本變量int、char……我們可以直接使用運算符 ==、<、>等等去比較。但是自定義類型我們應該如何處理呢?
一般情況下我們可以自己創(chuàng)建一個比較函數進行比較:
//判斷前面日期是否比后面大
//大返回true,小返回false
bool Greater(Date x, Date y)
{
if (x._year > y._year)
{
return true;
}
else if (x._year == y._year && x._month > y._month)
{
return true;
}
else if (x._year == y._year && x._month == y._month && x._day > y._day)
{
return true;
}
return false;
}
將此函數放入到類中才可以進行私有數據訪問,要不就將基本數據公有化!
上述函數可以輕松解決比大小的問題,但是還是有許多缺陷。比如:函數名的不規(guī)范就會導致我們不理解函數的作用。所以對于內置類型的比較C++針對起名字做出了一下規(guī)定:
函數名字為:關鍵字operator后面接需要重載的運算符符號。
函數原型:返回值類型?operator操作符(參數列表)
注意:
不能通過連接其他符號來創(chuàng)建新的操作符:比如operator@
重載操作符必須有一個類類型參數
用于內置類型的運算符,其含義不能改變,例如:內置的整型+,不能改變其含義
作為類成員函數重載時,其形參看起來比操作數數目少1,因為成員函數的第一個參數為隱
藏的this
.* :: sizeof ?: . 注意以上5個運算符不能重載。這個經常在筆試選擇題中出現。?
那針對以上函數我們就可以這樣修改:
bool operator>(const Date& x, const Date& y)
{
if (x._year > y._year)
{
return true;
}
else if (x._year == y._year && x._month > y._month)
{
return true;
}
else if (x._year == y._year && x._month == y._month && x._day > y._day)
{
return true;
}
return false;
}
在參數選擇時,我們選擇引用而不選擇直接傳參,這樣可以節(jié)約時間效率,不用調用拷貝構造函數。?
?這樣做我們用戶一眼就可以看出此函數的作用,是用來比大小的函數。但是這樣去調用函數時函數名還是太長了,而且不直白不美觀,所以我們在使用時可以使用非常簡單的方式進行調用:
bool ret1 = d1 > d2;
只需要一個運算符就可以調用此函數,是不是非常方便呢!編譯器可以幫助我們將這句話轉變?yōu)?,調用函數的語句。
注意:運算符重載與函數重載中都有重載二字,但是絕對是沒有任何關系的,函數重載是可以允許參數不同的同名函數,運算符重載是自定義類型可以直接使用運算符。不是姓“張”的都有血緣關系。
但是當我們萬事俱備之后進行編譯卻還是出現報錯:?這是為什么呢?
為什么會多一個參數呢?哪里多了?成員參數都會有一個隱藏的參數this指針。所以參數不匹配導致程序出問題。相當于我們在調用函數時使用了兩個參數,而設定的參數中卻有三個!
我們應該怎么解決問題呢?刪一個即可。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// Date(const Date& d) ?// 正確寫法
void print()
{
cout << _year << '/' << _month << '/' << _day << endl;
}
//Date(const Date& d) ?// 錯誤寫法:編譯報錯,會引發(fā)無窮遞歸
//{
// _year = d._year;
// _month = d._month;
// _day = d._day;
//}
bool operator>(const Date& y)
{
if (_year > y._year)
{
return true;
}
else if (_year == y._year && _month > y._month)
{
return true;
}
else if (_year == y._year && _month == y._month && _day > y._day)
{
return true;
}
return false;
}
private:
int _year;
int _month;
int _day;
};
//判斷日期是否相等
//bool Greater(Date x, Date y)
//bool Compare1(Date x, Date y)
int main()
{
Date d1;
Date d2(2022,10,23);
/*d1 == d2;
d1 > d2;*/
bool ret1 = d1 > d2;
int x = 1, y = 2;
bool ret = x > y;
return 0;
}
?我們將參數刪除一個即可,編譯器看就會轉換成d1.operator(d2)在進行轉換成d1.operator(&d1,d2)即可,地址就是this指針指向的內容。
我們學明白了運算符重載,那么在進行賦值運算符重載就非常easy了。
?賦值運算符重載
賦值運算符重載格式
參數類型:const T&,傳遞引用可以提高傳參效率
返回值類型:T&,返回引用可以提高返回的效率,有返回值目的是為了支持連續(xù)賦值
檢測是否自己給自己賦值
返回*this :要復合連續(xù)賦值的含義
class Date
{
public :
Date(int year = 1900, int month = 1, int day = 1)
?{
????_year = year;
????_month = month;
????_day = day;
?}
Date (const Date& d)
?{
????_year = d._year;
????_month = d._month;
????_day = d._day;
?}
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 ;
};
賦值運算符只能重載成類的成員函數不能重載成全局函數
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
// 賦值運算符重載成全局函數,注意重載成全局函數時沒有this指針了,需要給兩個參數
Date& operator=(Date& left, const Date& right)
{
if (&left != &right)
{
left._year = right._year;
left._month = right._month;
left._day = right._day;
}
return left;
}
// 編譯失?。?// error C2801: “operator =”必須是非靜態(tài)成員
原因:賦值運算符如果不顯式實現,編譯器會生成一個默認的。此時用戶再在類外自己實現
一個全局的賦值運算符重載,就和編譯器在類中生成的默認賦值運算符重載沖突了,故賦值
運算符重載只能是類的成員函數。?用戶沒有顯式實現時,編譯器會生成一個默認賦值運算符重載,以值的方式逐字節(jié)拷貝。注
意:內置類型成員變量是直接賦值的,而自定義類型成員變量需要調用對應類的賦值運算符
重載完成賦值
class Time
{
public:
Time()
{
_hour = 1;
_minute = 1;
_second = 1;
}
Time& operator=(const Time& t)
{
if (this != &t)
{
_hour = t._hour;
_minute = t._minute;
_second = t._second;
}
return *this;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 基本類型(內置類型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定義類型
Time _t;
};
int main()
{
Date d1;
Date d2;
d1 = d2;
return 0;
}
既然編譯器生成的默認賦值運算符重載函數已經可以完成字節(jié)序的值拷貝了,還需要自己實
現嗎?當然像日期類這樣的類是沒必要的。那么下面的類呢?驗證一下試試?
// 這里會發(fā)現下面的程序會崩潰掉?這里就需要我們以后講的深拷貝去解決。
typedef int DataType;
class Stack
{
public:
Stack(size_t capacity = 10)
{
_array = (DataType*)malloc(capacity * sizeof(DataType));
if (nullptr == _array)
{
perror("malloc申請空間失敗");
return;
}
_size = 0;
_capacity = capacity;
}
void Push(const DataType& data)
{
// CheckCapacity();
_array[_size] = data;
_size++;
}
~Stack()
{
if (_array)
{
free(_array);
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
private:
DataType *_array;
size_t _size;
size_t _capacity;
};
int main()
{
Stack s1;
s1.Push(1);
s1.Push(2);
s1.Push(3);
s1.Push(4);
Stack s2;
s2 = s1;
return 0;
}
?注意:如果類中未涉及到資源管理,賦值運算符是否實現都可以;一旦涉及到資源管理則必
須要實現。
文章來源:http://www.zghlxwxcb.cn/news/detail-721251.html
以上就是賦值運算符重載全部內容?。?!感謝大家觀看。?文章來源地址http://www.zghlxwxcb.cn/news/detail-721251.html
到了這里,關于探索C++賦值運算符重載的內部機制:手把手教你精通的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!