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

VC 開發經驗談(二續):幾何元素類別實作與 DLL 記憶體管理

     編輯:VC 教學

承接上篇,完成幾何元素基類 CMyBase、圓弧 CMyArc、多段線 CMyPolyLn、形狀容器 CShape 的完整實作,並解決跨 DLL 邊界的 new/delete 記憶體管理問題。

一、三維點結構與封裝類別

struct MYXYZ { double x, y, z; };

class CMyXYZ : public MYXYZ {
public:
    CMyXYZ() : x(0), y(0), z(0) {}
    CMyXYZ(const MYXYZ& xyz) : x(xyz.x), y(xyz.y), z(xyz.z) {}
    CMyXYZ(double x_, double y_, double z_) : x(x_), y(y_), z(z_) {}
    virtual ~CMyXYZ() {}
    operator MYXYZ() const { return *this; }
    const CMyXYZ& operator=(const MYXYZ& xyz) { x=xyz.x; y=xyz.y; z=xyz.z; return *this; }
};

提供拷貝建構子、指派運算子、隱性轉換,支援 Line(CMyXYZ(0,0,0), CMyXYZ(100,100,0)) 等臨時物件語法。

二、幾何元素基類

class CMyBase {
protected:
    CMyBase() {}
public:
    virtual int GetType() = 0;          // ISARC=1, ISPOLYLN=2, ISSHAPE=3
    virtual int Draw(long lDevice) = 0; // lDevice = (long)HDC
    virtual ~CMyBase() {}
};
  • protected 建構子防止直接實例化。
  • 純虛函式強制衍生類實作型別識別與繪圖。
  • long lDevice 而非 HDC,提升跨平台擴充性。

三、圓弧類別 CMyArc

class CMyArc : public CMyBase {
public:
    CMyArc(MYXYZ pc, MYXYZ ps, MYXYZ pe) : m_pc(pc), m_ps(ps), m_pe(pe) {}
    virtual int GetType() { return ISARC; }
    virtual int Draw(long lDevice) {
        double dR = sqrt(pow(m_ps.x-m_pc.x,2)+pow(m_ps.y-m_pc.y,2)+pow(m_ps.z-m_pc.z,2));
        ::Arc((HDC)lDevice,
              (int)(m_pc.x-dR), (int)(m_pc.y-dR),
              (int)(m_pc.x+dR), (int)(m_pc.y+dR),
              (int)m_ps.x, (int)m_ps.y, (int)m_pe.x, (int)m_pe.y);
        return 0;
    }
    virtual ~CMyArc() {}
    MYXYZ m_pc, m_ps, m_pe; // 圓心、起點、終點
};

四、多段線類別 CMyPolyLn(使用 STL list)

#pragma warning(disable:4786 4251 4273) // 抑制 STL 匯出警告
#include <list>
using namespace std;
typedef list<MYXYZ*> MYPOLYLN; // 存指標避免拷貝開銷

class CMyPolyLn : public CMyBase {
public:
    CMyPolyLn() { m_PolyLn.clear(); }
    virtual int GetType() { return ISPOLYLN; }
    virtual int AddPoint(MYXYZ* pxyz) {
        MYXYZ* p = new MYXYZ(*pxyz);
        m_PolyLn.insert(m_PolyLn.end(), p);
        return 0;
    }
    virtual int Draw(long lDevice) {
        HDC hdc = (HDC)lDevice;
        if (m_PolyLn.empty()) return 0;
        auto it = m_PolyLn.begin();
        MoveToEx(hdc, (int)(*it)->x*100+100, (int)-(*it)->y*100+200, NULL);
        for (; it != m_PolyLn.end(); ++it) {
            LineTo(hdc, (int)(*it)->x*100+100, (int)-(*it)->y*100+200);
        }
        return 0;
    }
    virtual ~CMyPolyLn() {
        for (auto p : m_PolyLn) delete p;
        m_PolyLn.clear();
    }
    MYPOLYLN m_PolyLn;
};

五、形狀容器 CShape(Composite Pattern)

class CShape : public CMyBase {
public:
    CShape() { m_List.clear(); }
    virtual int GetType() { return ISSHAPE; }
    virtual int Draw(long lDevice) {
        for (auto p : m_List) p->Draw(lDevice);
        return 0;
    }
    virtual ~CShape() {
        for (auto p : m_List) delete p;
        m_List.clear();
    }
    list<CMyBase*> m_List;
};

六、主程式測試碼

void CShapeView::OnDraw(CDC* pDC) {
    CShape shape;
    shape.m_List.push_back(new CMyArc(CMyXYZ(100,100,0), CMyXYZ(100,20,0), CMyXYZ(180,100,0)));

    CMyPolyLn* poly = new CMyPolyLn;
    poly->AddPoint(new MYXYZ{1,1,0});
    poly->AddPoint(new MYXYZ{2,2,0});
    poly->AddPoint(new MYXYZ{2,1,0});
    shape.m_List.push_back(poly);

    shape.Draw((long)pDC->m_hDC);
}

七、跨 DLL 記憶體管理陷阱與解決方案

問題:主程式 new 配置物件,DLL 中 delete 釋放 → Heap Corruption / Assertion Failure,因為 EXE 與 DLL 各自擁有獨立 CRT 堆疊。

方案對比

方案做法優點缺點
1. GlobalAlloc/GlobalFree用 GlobalAlloc(GMEM_FIXED, size) 替代 new,GlobalFree 替代 delete共享系統堆疊,跨 DLL 安全需手動呼叫建構子/解構子,繁瑣
2. 統一 CRT 版本 (推薦)EXE 與 DLL 專案設定 → C/C++ → Code Generation → Multithreaded DLL (Release) / Debug Multithreaded DLL (Debug)共享同一 CRT 堆疊,new/delete 自然配對所有模組必須用相同 CRT 版本、相同編譯器版本
3. 介面式釋放DLL 提供 DestroyShape(IShape*),內部呼叫 delete封裝記憶體管理,呼叫端無需知曉配置器需定義介面,增加複雜度

本專案採用方案 2,最符合現代 VC++ 開發規範,且零程式碼修改即可解決。

八、後續擴充方向

  • 支援線型、顏色、線寬等屬性(加入 CMyPen/CMyBrush 成員)。
  • 實作 HitTest、BoundingBox 支援選取/編輯。
  • 序列化至 XML/JSON,實現圖檔儲存與載入。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved