題目明確要求:
std::string**,非 MFC CString。String**,非 CMyString。operator/ 計算子字串出現次數、get_token() 分割語彙。原始碼完全不符合上述要求,以下提供符合規範的正確實作與錯誤分析。
class divide_empty_substring : public std::logic_error {
public:
const char* what() const throw() {
return "Divided by an empty substring";
}
};
std::string::size_type String::operator/(const String& sub) const {
if (sub.empty())
throw divide_empty_substring(); // 拋出例外優於回傳 0
std::string::size_type n = 0;
std::string::size_type i = 0;
while ((i = find(sub, i)) != std::string::npos) {
++n;
i += sub.length(); // 避免無限迴圈
}
return n;
}
關鍵點:
const 表示不修改物件狀態。std::string::npos 而非 -1。i += sub.length(),否則空字串會無限迴圈。嚴禁使用 static 區域變數! 題目敘述易誤導使用 static 計數器,但成員函式應使用成員變數追蹤狀態。否則多物件共用 static 變數會導致錯誤:
String str1, str2;
str1.get_token(); // 取得 str1 第一個 token
str2.get_token(); // 錯誤:取得 str2 的第二個 token(static 計數器共用)
int CMyString::operator/(const String& sub) {
if (sub.IsEmpty()) return 0;
int count = 0;
int ret = Find(sub);
if (ret == -1) return 0;
else if (ret <= GetLength()) // 條件永真,多餘
{
do {
count++;
ret = Find(sub, GetAt(ret)); // GetAt() 回傳字元,非索引!邏輯錯誤
} while (ret != -1);
}
return count;
}
GetAt(ret) 回傳位置 ret 的字元,非下一搜尋起始索引,導致邏輯完全錯誤。CString CMyString::get_token() {
static int callednum = 0; // 致命錯誤:static 共用於所有實例
int totalnum = operator/(' '); // 空格總數
if (totalnum == 0) return NULL;
int tokennum, ret1 = 0, ret2 = 0;
while ((ret1 = Find(' ', ret2)) != -1 && (ret2 = Find(' ', ret1)) != -1) {
// ret1, ret2 初始皆 0,永遠找到第一個空格 → 無限迴圈或錯誤
if (ret1 == ret2 - 1) totalnum--; // 相鄰空格合併
return Mid(ret1, ret2 - ret1); // 提早返回,callednum 不遞增
}
// 以下程式碼永遠不會執行...
if (ret2 == -1) return Right(GetLength() - ret1);
tokennum = totalnum;
(callednum++) %= tokennum; // tokennum 等於 totalnum,多此一舉
// 最後分支無返回值 → 未定義行為
}
static callednum 導致多物件狀態汙染。ret1=Find(' ', ret2) 與 ret2=Find(' ', ret1) 互相依賴初始值 0,邏輯崩壞。return 導致狀態更新失效,後半段死碼。CString 卻回傳 NULL,型別不匹配。static 區域變數造成跨實例干擾。此題考驗不僅是語法熟悉度,更是物件導向設計、標準庫運用與防禦性程式設計能力的綜合體現。