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

VC 開發經驗談(二):幾何元素類別架構設計與 STL 應用

     編輯:VC 教學

AutoCAD SHX 字型輪廓由圓弧與多段線組成,兩者共享「繪圖」等共同行為。本文展示如何抽象基類、封裝三維點、善用 STL list 建立可擴充的幾何元素類別體系。

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

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; }
};

設計考量:

  • 繼承 MYXYZ 而非組合,因為「是一個」關係成立,且可直接傳遞給需 MYXYZ* 的 C API。
  • 多重建構子支援:預設、拷貝、三參數、隱性轉換、指派運算子。
  • 使用 double 儲存座標,預留三維擴充空間。

二、幾何元素抽象基類

class CMyBase {
protected:
    CMyBase() {} // 防止直接實例化
public:
    virtual int GetType() = 0;          // 回傳 ISARC/ISPOLYLN/ISSHAPE
    virtual int Draw(long lDevice) = 0; // lDevice = (long)HDC
    virtual ~CMyBase() {}
};
  • protected 建構子強制衍生類使用。
  • 純虛函式確保所有衍生類實作型別查詢與繪圖。
  • long lDevice 而非 HDC/CDC*,降低平台耦合。

三、STL list 管理多段線頂點

#pragma warning(disable:4786 4251 4273)
#include <list>
using namespace std;
typedef list<MYXYZ*> MYPOLYLN; // 存指標:避免拷貝、支援多型、插入刪除 O(1)

class CMyPolyLn : public CMyBase {
public:
    CMyPolyLn() { m_PolyLn.clear(); }
    virtual int GetType() { return ISPOLYLN; }
    virtual int AddPoint(MYXYZ* pxyz) {
        m_PolyLn.insert(m_PolyLn.end(), new MYXYZ(*pxyz));
        return 0;
    }
    virtual int Draw(long lDevice) { /* 實作見下篇 */ }
    virtual ~CMyPolyLn() {
        for (auto p : m_PolyLn) delete p;
        m_PolyLn.clear();
    }
    MYPOLYLN m_PolyLn;
};

list 選擇理由:頂點頻繁尾端新增、中間插入刪除、順序遍歷繪圖,list 符合所有需求且迭代器穩定。

四、完整類別宣告

#define ISARC 1
#define ISPOLYLN 2
#define ISSHAPE 3

class CMyArc : public CMyBase {
public:
    CMyArc(MYXYZ pc, MYXYZ ps, MYXYZ pe) : m_pc(pc), m_ps(ps), m_pe(pe) {}
    CMyArc() {}
    virtual int GetType() { return ISARC; }
    virtual int Draw(long lDevice); // 實作見下篇
    virtual ~CMyArc() {}
    MYXYZ m_pc, m_ps, m_pe; // 圓心、起點、終點
};

typedef list<MYXYZ*> MYPOLYLN;

class CMyPolyLn : public CMyBase {
public:
    CMyPolyLn() { m_PolyLn.clear(); }
    virtual int GetType() { return ISPOLYLN; }
    virtual int AddPoint(MYXYZ* pxyz);
    virtual int Draw(long lDevice);
    virtual ~CMyPolyLn();
    MYPOLYLN m_PolyLn;
};

class CShape : public CMyBase { // Composite Pattern: 形狀 = 幾何元素集合
public:
    CShape() { m_List.clear(); }
    virtual int GetType() { return ISSHAPE; }
    virtual int Draw(long lDevice);
    virtual ~CShape();
    list<CMyBase*> m_List; // 存基類指標,支援異質容器
};

五、關鍵設計模式應用

模式應用處效益
Template MethodCMyBase 定義 Draw 流程骨架統一繪圖介面,衍生類只實作細節
CompositeCShape 含 list<CMyBase*>單一/群組物件統一操作,遞迴繪圖
Factory Method (潛在)未來可加入 CreateArc/CreatePolyLn封裝建構邏輯,支援序列化工廠

六、常見 STL 陷阱與對策

  • 指標擁有權模糊:明確規定「容器擁有指標,負責 delete」,析構函式必須遍歷釋放。
  • 跨 DLL 邊界傳遞 STL 容器:嚴禁。EXE/DLL 各自有獨立 STL 實例。改用介面傳遞迭代器或複製資料至純 C 陣列。
  • 匯出警告 C4251/4273:加上 #pragma warning(disable:4786 4251 4273) 或將 STL 成員移至 private 並提供存取函式。

七、下一步預告

下篇將給出 CMyArc::Draw、CMyPolyLn::Draw、CShape::Draw 完整實作、主程式測試碼,並深入解決跨 DLL new/delete 記憶體管理難題。

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