[英]Why does operator = return *this?
假設我想覆蓋operator =
所以我可以做類似的事情
Poly p1; // an object representing a polynomial
Poly p2; // another object of the same type
p2 = p1; // assigns all the contents of p1 to p2
然后在我對operator =
的實現中,我有這樣的東西:
Poly& Poly::operator=(const Poly &source) {
// Skipping implementation, it already works fine…
return *this;
}
不要介意實施,它已經可以正常工作了。
我擔心的是當你return *this
時會發生什么? 我知道它返回對對象的引用,但會發生這種情況嗎?
p2 = &p1
您return *this
這樣您就可以編寫普通的復合 C++ =
語句,例如:
Poly p1; //an object representing a polynomial
Poly p2;
Poly p2;
// ...
p3 = p2 = p1; //assigns all the contents of p1 to p2 and then to p3
因為那句話基本上是:
p3.operator=(p2.operator=(p1));
如果p2.operator=(...)
沒有return *this
你將沒有任何意義傳遞給p3.operator=(...)
。
p2 = p1
是p2.operator=(p1)
的簡寫。 它只是調用您的operator=
函數,該函數返回對p2
的引用,然后您將忽略它。 為了清楚起見,我們稱它為assign
而不是operator=
:
Poly& Poly::assign(const Poly &source) {
.
.
.
return *this;
}
現在代替p2 = p1
,你會寫
p2.assign(p1);
在這種情況下,調用assign
的結果將被忽略,但您不必忽略它。 例如,你可以寫:
p3.assign(p2.assign(p1));
使用operator=
而不是assign
,這就變成了
p3 = (p2 = p1);
但由於賦值是右結合的,這也可以寫成
p3 = p2 = p1;
這種能夠同時進行多項賦值的形式最初來自 C,並通過在operator=()
中返回*this
的約定保留在 C++ 中。
如果您無論如何都不需要鏈式賦值(如其他答案所示),則可能會試圖讓復制賦值運算符返回void
。 畢竟,鏈式賦值通常難以閱讀和理解,所以不允許它們可能被視為一種改進。
但是,一個經常被忽視的方面是void operator=(Poly& const)
意味着您的類型將不再滿足CopyAssignable
概念,這需要T&
返回類型。
不符合CopyAssignable
概念的類型不能正式用於某些標准容器操作,例如std::vector::insert
,這意味着以下看似無辜的代碼片段會產生未定義的行為,即使它可能運行得很好美好的:
#include <vector>
struct Poly
{
void operator=(Poly const&) {} // Poly is not CopyAssignable
};
int main()
{
std::vector<Poly> v;
Poly p;
v.insert(v.begin(), p); // undefined behaviour
}
正如 C++ 標准在 § 17.6.4.8/2.3 中解釋的那樣,它討論了對使用標准庫的程序的約束:
(...) 在以下情況下效果未定義:
(...) 對於在實例化模板組件時用作模板參數的類型,如果對該類型的操作未實現適用要求子條款 (...) 的語義。
當然,正是由於未定義的行為,編譯器才被允許忽略錯誤並使程序表現得很好,與明顯預期的行為相匹配。 但這不是必需的。
您還應該考慮到您無法預測Poly
類型的所有未來用途。 有人可能會編寫一些模板函數,例如:
template <class T>
void f(T const& t)
{
T t2;
T t3 = t2 = t;
// ...
}
此功能將不適用於您的Poly
類。
只要不違反此 C++ 約定,您就不會遇到麻煩。
當你返回 *this 時會發生什么?
在您的示例( p2 = p1;
)中,什么都沒有。 該方法將p1
復制到p2
並返回對調用代碼不使用的“this”對象的引用。
在p3 = p2 = p1;
,第一個調用是p2 = p1
,它將p1
復制到p2
並返回對p2
的引用。 然后調用代碼從該對p2
的引用復制到p3
(並忽略返回的對p3
的引用)。
(順帶一提:您的單元測試是否確保p1 = p1
正常工作?很容易忘記這種情況!)
返回對目標對象的引用允許賦值鏈接(級聯),並且類內的重載運算符遵循右關聯(單擊此處了解詳細的運算符重載規則)
Poly a, b, c;
a = b = c;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.