如何从 C 中的 extern "C" friend 函数访问类的不透明实现?

How to access opaque implementation of a class from an extern "C" friend function in C?

本文关键字:不透明 访问 实现 friend 中的 extern 函数      更新时间:2023-10-16

如果标题不太有意义,这里有一个简化的示例。考虑这个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...
}

正如你所看到的,我正试图实现桥或粉刺模式(和单态模式,虽然我不认为它是相关的这个特定的问题。)大多数情况下它是有效的,但在这个特定的实现而不是其他,我必须做一个信号处理程序,它必须是一个外部的"C"函数,而不是类的方法。如果代码是这样设置的,我得到以下错误:

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

我可以想到两种方法。

    将友元声明移到myclass中。

但是在这两种情况下,它都会违反接口和实现的分离,对吗?有没有更好的选择?

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

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

另一个选择是在myclass中创建一个公共清理函数,并且根本没有友谊。