首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 可變參數函數與自訂例外處理實作指南

     編輯:關於VC++

前言

C/C++ 的可變參數函數(如 printf 格式字串)與自訂例外類別是進階程式設計常用技巧。本文透過一個 CComboProp 類別實例,示範如何使用 va_list 處理不定數量參數,並定義繼承自 CException 的自訂例外 CSelItemException 進行錯誤傳遞。

可變參數函數實作

核心巨集:va_start、va_arg、va_end

  • va_start(va_list, last_fixed_param):取得第一個可變參數位址。
  • va_arg(va_list, type):依指定型別取得下一個參數並移動指標。
  • va_end(va_list):清理堆疊狀態。

約定:最後一個參數必須為 NULL 或 '\0' 作為結束標記。

範例 1:AddOption - 向屬性清單動態加入選項

BOOL CComboProp::AddOption(int nSeledIndex, LPCTSTR ItemString1, ...)
{
    va_list argList;
    va_start(argList, nSeledIndex);

    _variant_t vtDefault;
    int nCount = 0;
    LPCTSTR strArg;

    for (strArg = va_arg(argList, LPCTSTR); strArg != NULL; strArg = va_arg(argList, LPCTSTR)) {
        CBCGPProp::AddOption(strArg, FALSE);
        if (nSeledIndex == nCount++) vtDefault.SetString(strArg);
    }
    va_end(argList);

    if (nSeledIndex >= 0) {
        if (nSeledIndex < nCount) this->SetValue(vtDefault);
        else throw CSelItemException(nSeledIndex, nCount); // 索引超出範圍拋出例外
    }
    return TRUE;
}

範例 2:CreateCombo - 建立下拉選單並填入字串

CComboBox* CComboProp::CreateCombo(CWnd* pWndParent, CRect rect,
    int SeledIndex, LPCTSTR ItemString1, ...)
{
    CComboBox* pCombo = CBCGPProp::CreateCombo(pWndParent, rect);
    va_list argList;
    va_start(argList, SeledIndex);

    LPCTSTR strArg;
    for (strArg = va_arg(argList, LPCTSTR); strArg != NULL; strArg = va_arg(argList, LPCTSTR)) {
        pCombo->AddString(strArg);
    }
    va_end(argList);

    if (SeledIndex >= 0) {
        if (pCombo->GetCount() > SeledIndex) {
            if (pCombo->SetCurSel(SeledIndex) == CB_ERR)
                throw CSelItemException(SeledIndex, pCombo->GetCount());
        } else {
            throw &CSelItemException(SeledIndex, pCombo->GetCount()); // 指標拋出需拷貝建構子
        }
    }
    return pCombo;
}

自訂例外類別 CSelItemException

class CSelItemException : public CException {
public:
    CSelItemException(const int& SelIndex, const int& ItemCount) {
        m_IndextoSeled = SelIndex; m_ItemCount = ItemCount;
    }
    // 必須提供拷貝建構子,否則 throw 物件會編譯錯誤
    CSelItemException(CSelItemException& m) {
        m_IndextoSeled = m.m_IndextoSeled; m_ItemCount = m.m_ItemCount;
    }
    virtual ~CSelItemException() {}
    int m_IndextoSeled; // 嘗試選取的索引
    int m_ItemCount;    // 實際項目總數
};

關鍵點:

  • 繼承 CException 才能搭配 MFC TRY/CATCH 巨集。
  • 必須實作拷貝建構子,否則 throw CSelItemException(...) 會因無法複製物件而編譯失敗(錯誤 C2153)。
  • 拋出時可用 throw CSelItemException(...)(值傳遞)或 throw &CSelItemException(...)(指標傳遞),後者需確保物件生命週期。

捕捉與處理


TRY {
    pProp->AddOption(5, _T("A"), _T("B"), NULL); // 只有 2 項,索引 5 會失敗
}
CATCH(CSelItemException, e) {
    CString msg; msg.Format(_T("索引 %d 超出範圍 (總項目 %d)"), e->m_IndextoSeled, e->m_ItemCount);
    AfxMessageBox(msg);
}
END_CATCH

總結

掌握 va_list 三巨集與自訂例外類別撰寫規範,能讓函式介面更彈性、錯誤處理更物件化、更符合 MFC 架構風格。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved