如何从C中的extern“C”友元函数访问类的不透明实现?

时间:2013-05-10 19:23:25

标签: c++

如果标题没有意义,这里是一个精简的例子。考虑一下这个myclass.h:

// 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模式,虽然我不认为它与这个特定问题有关。)大多数它可以工作,但在这个特定的实现而不是其他,我必须创建一个信号处理程序,它必须是extern“C”函数而不是类的方法。如果代码设置如下,我会收到以下错误:

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

我可以想出两种解决方法。

  1. 将朋友声明移至myclass。
  2. make _impl public。
  3. 但在这两种情况下都会违反界面和实施的分离吗?还有更好的选择吗?

2 个答案:

答案 0 :(得分:0)

您已经将信号处理程序与您的实现紧密耦合,因此我只想将其作为myclass的朋友作为您的选项1。

另一个选择是在myclass中创建一个公共清理功能,而根本没有友情。

答案 1 :(得分:0)

我推荐的方法是让end_sig成为myclassImpl的静态方法。它将具有C链接,因此可以传递给signal,并且还可以访问任何必要的内部。不需要免费的朋友功能,它仍然隐藏在pimpl中。