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

Managed C++ 核心技巧:物件刪除、庫封裝、字串轉換與 Tab 控制項著色

     編輯:關於C++

Managed C++ (MC++) 連結原生 C++ 與 .NET 執行環境,本文彙整四大實務主題:托管物件刪除語意、原生庫封裝為 .NET 元件、String ↔ TCHAR* 雙向轉換、Tab 控制項背景色自訂。

一、托管物件刪除:delete 做什麼?

__gc class ManagedClass {
public:
    ManagedClass() { Console::WriteLine("ctor"); }
    ~ManagedClass() { Console::WriteLine("dtor"); } // 解構子 = Finalize
};
  • delete obj:立即呼叫解構子 (相當於 IDisposable::Dispose),但不釋放記憶體
  • 記憶體回收由 GC 非決定性執行,最終呼叫 Finalize (同解構子)
  • 測試輸出證明:delete 觸發即時解構,未 delete 者在主程式結束時由 GC 清理

最佳實務:實作 IDisposable

  • 解構子僅釋放非托管資源 (檔案控制代碼、資料庫連線、GDI 物件)
  • 公開 Dispose() 供 C#/VB.NET 呼叫
  • C++ 專用程式可用 delete,跨語言庫必須實作 IDisposable
  • VC++ 2005 (C++/CLI) 行為有變更,參考 Andy Rich 專欄與 C++/CLI 標準

二、封裝原生庫:從 Linked List 到 ArrayList

原生介面 (ListLib.h)

struct NativeNode {
    int a, b;
    TCHAR* str;
    NativeNode* next;
};
NativeNode* AllocateList(int count);
void FreeList(NativeNode* head);

Managed 包裝類別 (ListWrap.cpp)

public __gc class ManagedNode {
public:
    int a, b;
    String* str;
    // 無 next,改用 ArrayList 管理集合
};

public __gc class ListWrap {
public:
    static ArrayList* CreateList(int count) {
        NativeNode* native = AllocateList(count); // 呼叫原生 DLL
        ArrayList* managed = new ArrayList();
        for (NativeNode* n = native; n != 0; n = n->next) {
            ManagedNode* m = new ManagedNode();
            m->a = n->a;
            m->b = n->b;
            m->str = n->str; // TCHAR* → String* 隱性轉換
            managed->Add(m);
        }
        FreeList(native); // 立即釋放原生記憶體
        return managed;
    }
};

C# 客戶端呼叫

ArrayList list = ListWrap.CreateList(7);
foreach (ManagedNode n in list) {
    Console.WriteLine("{0}, {1}, {2}", n.a, n.b, n.str);
}

封裝策略比較

策略優點缺點
薄包裝 + 客戶端呼叫 FreeList單一轉換函數通用洩漏原生細節,客戶端需記得釋放
厚包裝 (本文採用)完全隱藏原生記憶體管理,.NET 風格 API每個建立函數需個別包裝

原則:能轉為托管物件盡量轉,讓 GC 管理記憶體,除非效能極度敏感。

三、String ↔ TCHAR* 雙向轉換

String → TCHAR* (需 pinning)

String __gc* s = S"Hello";
const wchar_t __pin* p = PtrToStringChars(s); // 釘住托管記憶體
// 現可安全傳給原生 API
// ANSI 版本:wcstombs 或 ATL W2A 宏
  • PtrToStringChars 回傳 __gc wchar_t*,指向 String 內部緩衝區
  • 必須 __pin:防止 GC 移動記憶體導致指標失效
  • MFC CString 直接支援 char*/wchar_t* 指派,無需手動轉換

TCHAR* → String

String* s = new String("Hello"); // 或 S"Hello"
s = "World"; // 隱性轉換 char* → String*

四、Tab 控制項背景色自訂 (MFC)

核心類別:CColorTabCtrl

  • 繼承 CTabCtrl,設定 TCS_OWNERDRAWFIXED 模式
  • 覆寫 DrawItem:FillSolidRect 背景、SetTextColor、DrawText
  • 提供 SetColor(COLORREF bg, COLORREF fg) 設定顏色

屬性頁整合

class CMyPropSheet : public CPropertySheet {
    CColorTabCtrl m_tabCtrl;
    // OnInitDialog:
    HWND hTab = (HWND)SendMessage(PSM_GETTABCONTROL);
    m_tabCtrl.SubclassDlgItem(::GetDlgCtrlID(hTab), this);
    m_tabCtrl.SetColor(RGB(255,255,255), RGB(255,0,0)); // 白底紅字
};

頁面背景同步:CColorPropertyPage

BOOL CColorPropertyPage::OnEraseBkgnd(CDC* pDC) {
    CRect rc; GetClientRect(&rc);
    pDC->FillSolidRect(rc, m_clrBackground);
    return TRUE; // 抑制預設擦除
}
  • 需額外處理 WM_CTLCOLOR 統一子控制項背景色
  • 標籤邊框 3D 色需自繪 WM_PAINT,工程量大
  • .NET WinForms 只需 ctl.BackColor = Color.Aquamarine; — 考慮遷移

總結

Managed C++ 是跨越原生與托管世界的橋樑。理解 delete 與 GC 的分工、善用 __pin 安全互操、封裝原生庫時優先轉換為托管集合、UI 客製化權衡成本與收益,是高效開發混合模式應用的關鍵。

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