2013-07-03 106 views
2

我想編寫一個包裝c結構體的C++類。下面是一個簡單的例子 C結構:C++的C++類包裝器struct

struct POINT { 
    long x; 
    long y; 
} 

現在我假定這下面的類,但我不知道這是否是「高性能」,也不是很好的C++風格。我不想使用不必要的變量或函數調用。如果你改進了我的代碼,這將是非常好的:)。

這個類的基本思想是它只是結構的包裝器/處理器。這就是爲什麼setStructgetStruct可以直接修改私有數據,並且它只是一個指針。其他成員總是被命名爲set<Attribute>get<Attribute>

如果你使用setStruct唯一的缺點我可以想到的是,結構可以刪除由於範圍,使指針是「無效」。

namespace wrapper { 
class POINT { 
    ::POINT * POINT_; 

public: 
    POINT() { 
    POINT_ = new ::POINT; 
    } 
    ~POINT() { 
    delete POINT_; 
    } 
    inline void setX(long x) { 
    POINT_->x = x; 
    } 
    inline long getX() { 
    return POINT_->x; 
    } 
    inline void setY(long y) { 
    POINT_->y = y; 
    } 
    inline long getY() { 
    return POINT_->y; 
    } 
    inline void setStruct(::POINT * __POINT) { 
    POINT_ = __POINT; 
    } 
    inline ::POINT * getStruct() { 
    return POINT_; 
    } 
}; 
} 
+1

爲什麼不只是保存2個LONG成員變量並定義一個隱式轉換運算符爲POINT?也絕對沒有理由持有指向:: POINT的指針而不是:: POINT本身。 – Borgleader

+2

'_POINT'是[保留標識符](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c- identifier)。此外,除非可能在'std :: make_unique'中使用'new',直到C++ 14或者除非你是1%的人,否則實際上它必須具有特定的場景。 – chris

+0

瞭解pimpl習語,以便在實現文件(.cpp)中使用你的POINT結構體(.cpp) –

回答

2

在這種情況下,您最好使用繼承而不是組合。它將消除管理額外資源的需要,並允許您的「包裝器」充當POINT,而不是需要整個POINT結構的訪問器和增變器。

namespace wrapper { 
    class Point : public ::POINT 
    { 
    public: 
     Point() { } 
     ~Point() { } 

     // The following accessors/mutators may not be necessary. 
     // They can however be handy with code that requires a pointer to 
     // member function (i.e. transformations) 
     void setX(long nx) { x = nx; } 
     long getX() { return x; } 
     void setY(long ny) { y = ny; } 
     long getY() { return y; } 

     // copy assignment operators 
     Point& operator=(const POINT& p) 
     { 
      x = p.x; 
      y = p.y; 
      return *this; 
     } 

     Point& operator=(const Point& p) 
     { 
      x = p.x; 
      y = p.y; 
      return *this; 
     } 
    }; 
} 

如果你想避免的POINT成員直接訪問您可以使用私有繼承。您還可以提供一個轉換運算符,以允許從PointPOINT的隱式轉換。這將取代POINT* getStruct()成員函數,但仍允許您輕鬆地將它用於需要POINT作爲參數的函數。

namespace wrapper { 
    // Use private inheritance to prevent direct access to the 
    // members of POINT 
    class Point : private POINT 
    { 
    public: 
     Point() { } 
     ~Point() { } 

     // Copy constructor 
     Point(const ::POINT& p) { x = p.x; y = p.y; } 

     // Accessor/mutators 
     void setX(long nx) { x = nx; } 
     long getX() { return x; } 
     void setY(long ny) { y = ny; } 
     long getY() { return y; } 

     // Allow implicit conversions to POINT* when necessary 
     // Replaces getStruct() 
     operator ::POINT*() { return this; } 
     operator const ::POINT*() const { return this; } 

     // Copy assignment operators 
     Point& operator=(const POINT& p) 
     { 
      x = p.x; 
      y = p.y; 
      return *this; 
     } 

     Point& operator=(const Point& p) 
     { 
      x = p.x; 
      y = p.y; 
      return *this; 
     } 
    }; 
} 

extern "C" void someCFunction(POINT *); 

int main() 
{ 
    POINT cp; 
    wrapper::Point p; 

    p.x = 0; // FAIL 
    p.setX(0); // OK 
    p = cp; // OK 

    // No need to call getPoint(). 
    someCFunction(p); 
} 

注:我已刪除了使用inline,因爲他們是不必要的。在類定義中定義的函數已經內聯(見$ 7.1.2/3)。榮譽Chris提醒我。

+0

你真的需要setter/getters嗎?你公開從一個結構體繼承,所以我認爲這些成員也將被公開? – Borgleader

+0

我曾考慮過去掉它們,但決定不去。我添加了一個關於他們爲什麼仍然有用的說明。這很難說,因爲我不知道OP要用包裝完成什麼。 –

+0

這是個好主意。但是我會用'private'代替'public'來繼承。有沒有反對此的論據? – andrew

0

如前所述_POINT是保留名稱,因爲它與_ +大寫字母開頭。

使用所有類型名稱大寫是主觀的,但我傾向於遠離它。

如果您複製它,或者將基於堆棧的POINT的地址傳遞到setStruct,那麼您的類將遇到各種問題(雙刪除,刪除非堆內存等)。

如果您只是按價值撰寫,您的課程將會簡單得多,並且不易出錯。爲了複製更多的數據,你可以節省一定程度的間接性,但是可能會有更好的緩存,而不是間接尋找內存兩次。

getStructsetStruct函數明確地轉換爲C結構和從C結構轉換,沒有任何實際問題。

但是我的問題在於:你的C++包裝器爲你提供的C-struct不是什麼?無論如何,您只是將包裝的方法提供給各個屬性,而不是某種類別的接口來執行其他類的操作。在這種情況下,我實際上看不出有什麼理由使用包裝器(除非您打算將調試邏輯添加到getter和setter中,以便您可以更輕鬆地執行程序流程)。

+0

我將'POINT_'改爲'_POINT'。我怎樣才能避免這個問題。你能否把它更詳細地描述一下並舉一些例子? – andrew

+0

感謝您的編輯。是的,我想提供更多的功能:)。 – andrew