2011-10-13 69 views
0

漏出外部I型具有在報頭中定義像這樣(縮寫)的類:避免在C++類

class CairoRenderer 
{ 
public: 
    CairoRenderer(); 
    ~CairoRenderer(); 
... 
protected: 
    cairo_t* m_context; 
    cairo_surface_t* m_surface; 
}; 

cairo_t和cairo_surface_t是由Cairo圖形庫定義的類型。

我遇到的問題是,如果我想從另一個庫或應用程序使用此類或其派生類,我需要包含cairo標頭,因爲我通過CairoRenderer標頭「泄漏」開羅類型。我希望在同一個庫中的這個類(或它的任何子類)可以在外部使用,而不需要在開羅庫中包含cairo頭或鏈接。

所以,我想未來的事情是使用平普爾技術爲每Wikipedia例子,因爲它看起來像它會做什麼,我想實現:

CairoRenderer.h(略)

class CairoRenderer 
{ 
... 
protected: 
    struct CairoRendererImpl; 
    CairoRendererImpl* m_pimpl; 
}; 

CairoRenderer.cpp(略)

#include "CairoRenderer.h" 
#include "cairo.h" 

.... 

struct CairoRenderer::CairoRendererImpl 
{ 
public: 
    CairoRendererImpl() : m_surface(NULL), m_context(NULL) { } 
    ~CairoRendererImpl() 
    { 
     cairo_surface_destroy(m_surface); 
     cairo_destroy(m_context); 
    } 

    void Initialize(cairo_t* context, cairo_surface_t* surface) 
    { 
     m_context = context; 
     m_surface = surface; 
    } 

    cairo_surface_t* surface() { return m_surface; } 
    cairo_t* context() { return m_context; } 

private: 
    cairo_surface_t* m_surface; 
    cairo_t* m_context; 
}; 

CairoRenderer::CairoRenderer() : m_pimpl(new CairoRendererImpl()) { ... } 

CairoRenderer::~CairoRenderer() { delete m_pimpl; } 

我的問題是,當我嘗試從一個派生類訪問m_pimpl成員,我得到的編譯器錯誤:

error C2027: use of undefined type 'CairoRenderer::CairoRendererImpl' 

我在做pimpl錯了嗎?或者,我甚至想做甚麼?

+1

你想從一個派生類訪問PIMPL爲什麼呢? pimpl的整個存在的目的是隱藏一個類的實現細節。如果有的話,派生類應該只使用基類的接口。 – wilhelmtell

+0

主要目標是從外部代碼隱藏cairo_t和cairo_surface_t。 Pimpl看起來像解決方案,但顯然不是 – jumpinjackie

回答

4

您正確使用平普爾成語,那是你的問題。您已將隱藏的CairoRendererImpl的定義從全部外部代碼,包括派生類中的代碼。

首先,我想質疑具有數據成員和非虛擬析構函數的基類的價值。你應該看看你想要子類CairoRenderer的基本原因,並考慮替代解決方案。

如果要支持子類,但是隻有你的庫中的類,那麼,你應該把CairoRendererImpl定義爲可以由所有相關類的實現文件包含一個共享的頭文件在CairoRenderer heirachy。

+0

這樣保護不會做我認爲它在這方面做了什麼? – jumpinjackie

+0

你的建議解決方案,@haavee進一步詳細解釋了這個訣竅!乾杯。 – jumpinjackie

+0

@jumpinjackie如果不知道你認爲保護的是什麼,我無法回答,但是要注意的重要一點是訪問規範適用於名稱,而不適用於事物。 'protected'允許子類使用名稱'CairoRenderer :: CairoRendererImpl'(例如,爲函數或數據成員聲明參數),但即使'CairoRenderer :: CairoRendererImpl'是'private',子類仍然可以使用和訪問'm_pimpl'如果'm_pimpl'被聲明爲'protected'。你的代碼沒有被編譯的原因是你試圖使用已聲明但未定義的類。 – Mankarse

0

我認爲struct CairoRenderer::CairoRendererImpl是錯誤的。既然你不使用命名空間,這樣一個簡單的定義就足夠了:

struct CairoRendererImpl 
{ 
    ... 
} 

你也需要調整您的CairoRenderer類位:

struct CairoRendererImpl; 

class CairoRenderer 
{ 
... 
protected: 
    CairoRendererImpl* m_pimpl; 
}; 
+0

這不是問題所在。 'CairoRenderer :: CairoRendererImpl'是引用'CairoRendererImpl'的正確方法。 – Mankarse

1

pimpl習語用得好。

,以避免必須包括cairo.h文件(S)的方法是有,你CairoRenderer.h提交報表(即forward declaration

class CairoRendererImpl; 

,並留在這一點;做不是包括CairoRendererImpl。因爲這將需要拖拽cairo.h的定義。

你可以做到這一點,因爲CairoRenderer只需要一個指針來實現 - 只要你不實際調用從headerfile任何方法(如內聯函數)的編譯器並不需要看到的完整的聲明CairoRendererImpl類。

在CairoRenderer.cc中,你可以包含CairoRendererImpl.h文件(它會得到cairo.h的東西,但在這一點上,這是你真正想要/需要的)。

心連心, ^ h