初學 C++ 時常遇到兩類經典錯誤:拷貝建構子參數未加 const 導致無法接受暫時物件,以及 數學函式參數型別不匹配。本文以一個 Point-Line 幾何類為例,逐步修正編譯錯誤與邏輯缺陷。
class Point {
public:
Point(int xx=0, int yy=0) : x(xx), y(yy) {}
Point(Point &p); // ❌ 非 const 參考,無法綁定暫時物件
// ...
};
class Line {
public:
Line(Point &pp1, Point &pp2); // ❌ 同理
Line(int x1, int y1, int x2, int y2) : p1(x1,y1), p2(x2,y2) {
int x = static_cast(p1.GetX() - p2.GetX()); // ❌ static_cast 缺少目標型別
int y = static_cast(p1.GetY() - p2.GetY());
len = sqrt(x*x + y*y); // ❌ sqrt 需 double,傳入 int 可能精度損失/警告
}
Line(Line &l1); // ❌ 同理
// ...
};
#include
#include
using namespace std;
class Point {
public:
Point(int xx = 0, int yy = 0) : x(xx), y(yy) {}
// ✅ 加上 const,可接受暫時物件與常數物件
Point(const Point &p) : x(p.x), y(p.y) {
cout << "Point 拷貝建構子" << endl;
}
int GetX() const { return x; } // ✅ 加 const
int GetY() const { return y; }
private:
int x, y;
};
class Line {
public:
Line() : len(0) { cout << "Line 預設建構子" << endl; }
// ✅ 參數加 const
Line(const Point &pp1, const Point &pp2) : p1(pp1), p2(pp2) {
calcLen();
}
Line(int x1, int y1, int x2, int y2) : p1(x1, y1), p2(x2, y2) {
calcLen();
}
Line(const Line &l1) : p1(l1.p1), p2(l1.p2), len(l1.len) {
cout << "Line 拷貝建構子" << endl;
}
double GetLen() const { return len; } // ✅ 回傳 double 更精確
~Line() {}
private:
Point p1, p2;
double len; // ✅ 用 double 存儲長度
void calcLen() {
double dx = static_cast(p1.GetX() - p2.GetX()); // ✅ 明確轉 double
double dy = static_cast(p1.GetY() - p2.GetY());
len = sqrt(dx * dx + dy * dy); // ✅ sqrt 接收 double
}
};
int main() {
Point p1(3, 7), p2(9, 4);
Line line(p1, p2); // 呼叫 Line(const Point&, const Point&)
Line line2(line); // 呼叫 Line(const Line&)
cout << "The length of the line is: " << line.GetLen() << endl;
cout << "The length of the line2 is: " << line2.GetLen() << endl;
return 0;
}
| 錯誤類型 | 原寫法 | 修正 | 原因 |
|---|---|---|---|
| 拷貝建構子參數 | Point(Point &p) | Point(const Point &p) | 非 const 參考無法綁定右值(如 Point()、函式回傳值) |
| static_cast 語法 | static_cast(p1.GetX()-p2.GetX()) | static_cast | 必須指定目標型別 <type> |
| sqrt 參數型別 | sqrt(x*x + y*y) (x,y 為 int) | sqrt(double(dx*dx + dy*dy)) | sqrt 多載為 double/float/long double,整數會隱性轉換但可能精度損失/警告 |
| 長度儲存型別 | int len | double len | 幾何長度通常非整數,int 會截斷 |
| Getter 加 const | int GetX() | int GetX() const | 允許在 const 物件上呼叫,符合語意 |
開啟 -Wall -Wextra -Wpedantic (GCC/Clang) 或 /W4 (MSVC),上述錯誤在編譯期即可被攔截:
binding reference of type 'Point&' to 'const Point' discards qualifiersmissing template arguments before '(' token (static_cast)conversion from 'int' to 'double' may alter its valueC++ 型別系統嚴格而強大:拷貝建構子必須取 const 參考、數學運算盡早轉 double、唯讀方法標記 const。養成這些習慣,可消除 80% 以上的初學者編譯/執行期錯誤,寫出型別安全、效能穩健的 C++ 程式碼。