2013-05-10 68 views
1

如果標題不太合理,下面是一個精簡的例子。考慮這個myclass.h:如何從C中的extern「C」friend函數訪問類的不透明實現?

// Compiled with g++ 4.7 and -std=c++0x -pedantic -Wall -Wextra on Linux 
class myclass { 
public: 
    myclass()=default; 
    void init(); 

private: 
    struct myclassImpl; 
    static myclassImpl _impl; 
}` 

和myclass.cpp

#include <csignal> 
using namespace std; 
#include "myclass.h" 

extern "C" { 
    void end_sig(int); 
} 

struct myclass::myclassImpl { 
    friend void end_sig(int); 

    myclassImpl()=default; 
    void cleanup(); 
} 

myclass::myclassImpl myclass::_impl; 

extern "C" { 
    void end_sig(int /* sig */) { 
     myclass::_impl.cleanup(); 
    } 
} 

void myclass::init() { 
    signal (SIGINT, end_sig); 
} 

void myclass::myclassImpl::cleanup() { 
    // stuff... 
} 

正如你所看到的,我想實現的橋樑或PIMPL模式(與模式的Monostate雖然我不認爲它與這個特定的問題有關)。大多數情況下,它可以工作,但在這個特定的實現中,而不是其他的,我必須建立一個信號處理程序,它必須是一個外部「C」函數而不是該類的一個方法。如果代碼設置這樣的,我得到以下錯誤:

In function ‘void end_sig(int)’:  
error: ‘myclass::myclassImpl myclass::_impl’ is private 

我能想到的解決此兩種方式。

  1. 將朋友聲明移到myclass中。
  2. make _impl public。

但是在這兩種情況下,它會違反界面和執行權的分離嗎?有沒有更好的選擇?

+0

你不能有一個getter,返回一個指向proc/func /方法的指針,無論哪個術語在這個上下文中是合適的? – 2013-05-10 19:25:56

+0

如果所有成員都已經公開,myClassImpl中的friend語句不會執行任何操作。 – krsteeve 2013-05-10 19:57:23

回答

0

我這樣做,我建議,使end_sig靜態方法myclassImpl。它將有C鏈接,因此可以傳遞到signal,並且還可以訪問任何必要的內部。不需要免費的朋友功能,它仍然隱藏在pimpl中。

+0

謝謝!我沒有足夠的聲望投票給你,但這個建議完美地起作用。我最初考慮過一個靜態方法,但是我認爲它可能仍然有一個這個指針或一些不適合傳遞給C函數的東西。我想我錯了。 – Jaldhar 2013-05-11 15:52:51

0

你已經緊緊的信號處理程序連接到您的實現,所以我只想讓它的myclass一個朋友,因爲你的選擇1.

另一種選擇是做一個公開的清理功能myclass並沒有友誼在所有。

+0

感謝您的回答。有幾個不同的實現,只有這個需要信號處理程序,所以myclass似乎是朋友聲明的錯誤地方。 (因爲krsteeve注意myClassImpl會因爲成員公開而錯誤。) – Jaldhar 2013-05-11 15:49:25