RMB RMB::operator +(RMB b) {
yuan = yuan + b.yuan; // 修改了左操作數 this 的成員!
jiao = jiao + b.jiao;
fen = fen + b.fen;
// ... 進位邏輯
return RMB(yuan, jiao, fen);
}
運算符 + 應為純函數,不修改操作數。但代碼中直接修改了 this->yuan、jiao、fen,導致:
e = c + d; 執行後,c 的值被永久修改(元、角、分均增加)。f = d - c; 使用的是 已被修改的 c,結果當然錯誤。c1, d1 重新初始化,結果正確,印證了副作用。RMB RMB::operator +(const RMB& b) const { // const 保證不修改 this
int ny = yuan + b.yuan;
int nj = jiao + b.jiao;
int nf = fen + b.fen;
// 進位處理(使用局部變量)
if (nf >= 10) { nf -= 10; nj++; }
if (nj >= 10) { nj -= 10; ny++; }
return RMB(ny, nj, nf); // 返回新對象
}
RMB RMB::operator -(const RMB& b) const {
int ny = yuan, nj = jiao, nf = fen;
// 借位邏輯
if (nf < b.fen) {
if (nj > 0) { nf += 10; nj--; }
else if (ny > 0) { ny--; nj += 9; nf += 10; }
else { /* 處理負數或拋出異常 */ }
}
nf -= b.fen;
if (nj < b.jiao) {
if (ny > 0) { ny--; nj += 10; }
else { /* 處理負數 */ }
}
nj -= b.jiao;
ny -= b.yuan;
return RMB(ny, nj, nf);
}
| 原則 | 做法 | 理由 |
|---|---|---|
| 參數傳 const 引用 | const RMB& b | 避免拷貝開銷,防止誤修改參數 |
| 成員函數加 const | operator+(...) const | 編譯器強制檢查不修改 this,語義明確 |
| 使用局部變量計算 | int ny=yuan+... | 不污染原對象,線程安全 |
| 返回值而非引用 | RMB 而非 RMB& | 返回臨時對象,生命週期由調用方管理 |
int main() {
RMB c(1, 2, 1), d(3, 3, 3);
RMB e = c + d; // c 不變
RMB f = d - c; // 使用原始 c
c.display(); // 仍為 1元2角1分
d.display(); // 仍為 3元3角3分
e.display(); // 4元5角4分
f.display(); // 2元1角2分
}
運算符重載的核心規範:「不修改操作數,返回新值」。原代碼在 operator+ 中修改 this 導致連續調用時狀態污染。加上 const 資格、使用局部變量計算、傳 const 引用,可從語法層面杜絕此類 Bug。