我可以在C中存储指向C++类的指针吗?

3

我该如何在C结构体中存储一个指向C++类的指针?

我正在使用一个基于C结构体的API(MaxMSP)。然而,我想要使用C++。我尝试将我的类的指针存储在void*中,但是在删除它时(在C++中),会导致程序崩溃。

extern "C" void* MyClass_New(){
     MyClass* temp = new MyClass();
     return (void*)temp;
}

extern "C" void MyClass_Delete(void* myclass){
      delete (MyClass*)myclass;  //<--- this line crashes.
}

我知道这样做很丑陋且危险,但我看不到其他的方法。你呢?

我本以为void*足以跟踪C++类,但在将void*强制转换后调用delete会导致崩溃。

以下是我最简可复现的示例。

.c:

int main(int argc, const char * argv[]) {

    void* temp;
    temp= MyClassTranslator_New(4);   
    MyClassTranslator_Kill(temp);


    return 0;
}

.hpp

#ifndef m2ot_base_hpp
#define m2ot_base_hpp


#if defined __cplusplus



extern "C" class MyClassTranslator
{

    private :
        long num;

    public:
        MyClassTranslator(const long num);
        ~MyClassTranslator(){;};
        MyClassTranslator( const MyClassTranslator &obj);


        long getNum(void){return this->num;};


};

extern "C"  void* MyClassTranslator_New(const long num);

extern "C"  void MyClassTranslator_Kill(void* thisc);


#endif

#endif /* m2ot_base_hpp */


C++文件


MyClassTranslator::MyClassTranslator( const MyClassTranslator &that){
    this->num=that.num;
}

extern "C"  void* MyClassTranslator_New(const long num)
{
    MyClassTranslator* temp= new MyClassTranslator(num);

    return static_cast<void*> (temp);
}

extern "C"  void MyClassTranslator_Kill(void* thisc){
    delete static_cast<MyClassTranslator*>(thisc);
}


MyClassTranslator::MyClassTranslator(const long num){
    this->num=num;
}


我认为这应该可以工作(尽管严谨性要求使用reinterpret_cast)。因此,问题必须出现在未显示的代码中。因此,您需要在阅读stackoverflow.com的[帮助]并了解提供[mre]的要求后,编辑您的问题,以便任何人都可以编译和运行它们自己,以重现您的问题。否则,没有人能够帮助您。 - Sam Varshavchik
Ted,我不太确定这是什么意思,但API是商业应用MaxMSP的SDK,完全使用C语言编写。(我是第三方开发者) - Audiomatt
1
然后,您需要了解正在创建的类的内部源代码。如果构造函数和/或析构函数存在问题,那么当然会出现奇怪的行为,就像我给您一个具有错误析构函数的类并调用delete一样。 - PaulMcKenzie
你所发布的代码应该会出现错误,因为temp= MidiToOneToneTranslator_New(4);这行代码中函数的声明不可见(你将声明隐藏在了__cplusplus测试后面)。段错误可能是尝试运行错误代码的结果。如果你没有看到错误消息,请检查你的编译器设置(或者检查你是否真的发布了真实的代码)。 - M.M
1
@Audiomatt 在你的 .c 文件中,你从未包含函数声明。extern "C" 行只包含在你的 .cpp 文件中。你使用了 #if defined __cplusplus 来使头文件在不同的包含方式下看起来不同。 - M.M
显示剩余23条评论
1个回答

2

我能在C语言中存储C++类的指针。

是的。

但是,在C++中删除它会导致崩溃。

有几种可能性:

  • 您传递给MyClass_Delete的指针不是由MyClass_New创建的。
  • 您将相同的指针多次传递给MyClass_Delete
  • 该类的析构函数崩溃了。

关于风格:

MyClass_New中的转换是多余的。

我建议不要在C++中使用C样式转换。您可以使用static_castvoid*转换。

您可以使用包装器,例如:

struct MyClass_handle {
    void* ptr;
};
struct MyClass_handle MyClass_New();
void MyClass_Delete(struct MyClass_handle myclass);

使用类型化的句柄可以更容易地捕捉到不正确的使用方式。

原始答案。


我在上面包含了我的代码。我不认为自己会做这么傻的事情,但就像我在其他地方说的那样,我是一个初学者。 - Audiomatt
包含一个最小可重现的示例。请原谅.c文件中必要的API代码,相关的测试代码在底部。 - Audiomatt
@Audiomatt 您的示例对我来说运行良好: https://wandbox.org/permlink/SHc57gFPCamsyiR4 - eerorika
有趣的是,在wandbox上使用clang似乎不起作用。我正在运行支持c++ 11的libc++。我敢打赌这是构建设置中的某些玄学问题。等等,缺少声明在哪里?我是不是漏掉了一些愚蠢的东西? - Audiomatt
@Audiomatt 当您更改编译器时,它会清除“编译器选项”对话框,而我正试图使用该对话框来传递C源文件。当我尝试使用clang时,它发出了明确的警告:“警告:在C++模式下将'c'输入视为'c++',此行为已弃用[-Wdeprecated]”。因此,正如我在GCC的情况下所怀疑的那样,我的演示并不是纯粹的复制,因为C文件实际上并没有被编译为C。 - eerorika
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接