2013-01-08 119 views
0

我試圖圍繞外部C API創建僅頭文件C++庫。 C API使用void *指針作爲句柄。 這裏的想法:僅頭文件庫循環依賴

// resource.hpp 
class Resource { 
public: 
    // RAII constructor, destructor, etc. 
    // ... 
    void do_something(const Handle & h) { 
     do_something_impl((void *) h); 
    } 
}; 

// handle.hpp 
class Handle 
{ 
public: 
    Handle(size_t n, const Resource & res) 
     : p_(res.allocate(n)), res_(res) {} 

    // cast operation 
    operator void *() const { return p_; } 

private: 
    void * p_; 
    Resource & res_; 
}; 

這裏的問題是,(一)該手柄具有保留對資源的引用,和(b)所需要的資源,以便能夠在手柄轉換成爲void *。不幸的是,這導致了循環依賴。

任何想法如何重組這?

注意:答案不是簡單地「包含xxx.hpp」或轉發聲明其中一個類。 這需要重新調整,我只是不太明白。

class Handle作爲前向聲明添加到資源文件的頂部不起作用,因爲(void *)轉換是Resource仍然看不到的Handle定義的一部分。同樣,將演員改爲void * ptr()成員函數也會導致相同的問題。

將函數定義移動到.cpp文件也不是答案 - 它需要僅用於標題。

+1

[當使用向前聲明?](http://stackoverflow.com/questions/553682/when-to-use-forward -claclaration) – Joe

+0

除了使用前向聲明之外,請確保使用標頭警衛。 – drescherjm

+0

@Joe:向前聲明在這裏不起作用(見編輯)。 –

回答

1

那麼,它的模板來救援(又來了!):

// resource.hpp 
class Resource; 
template<typename TResource> class Handle; 

class Resource { 
public: 
    // RAII constructor, destructor, etc. 
    // ... 
    void do_something(const Handle<Resource> & h) { 
     do_something_impl((void *) h); 
    } 
}; 

// handle.hpp 
template<class TResource> 
class Handle { 
public: 
    Handle(size_t n, const TResource & res) 
     : p_(res.allocate(n)), res_(res) {} 

    // cast operation 
    operator void *() const { return p_; } 

private: 
    void * p_; 
    TResource & res_; 
}; 
2

不要將頭文件包含在彼此中,而應該有一個前向聲明這些類。這樣他們可以用作參考或指針。

在resource.hpp

所以:

class Handle; 

class Resource { 
public: 
    // RAII constructor, destructor, etc. 
    // ... 
    void do_something(const Handle & h) { 
     do_something_impl((void *) h); 
    } 
}; 

而且在handle.hpp:

class Resource; 

class Handle 
{ 
public: 
    Handle(size_t n, const Resource & res) 
     : p_(res.allocate(n)), res_(res) {} 

    // cast operation 
    operator void *() const { return p_; } 

private: 
    void * p_; 
    Resource & res_; 
}; 

由於您使用的void*類型轉換操作符的功能do_something裏面,你必須以移動實現到一個單獨的源文件中。在該源文件中,您可以包含兩個頭文件,因此可以訪問所有功能。

+0

@ Joachim - 在vs2010中,這給出了「無法從'const Handle&h'轉換爲'void *';源或目標的類型不完整,換句話說,Resource無法看到'operator void *()' 。 –

+0

此外,爲handle.hpp添加'class Resource'將不起作用,因爲Handle需要看到Resource.allocate()成員函數! –

+0

@DavidH然後你必須在'handle中包含'resource.hpp'文件.hpp'。只要你不做相反的事情也沒關係,至於錯誤,那是因爲你試圖將非指針類型轉換爲指針類型。 –