2

我的问题的本质是:

在 ac 函数中创建新对象并将对该新对象的一些引用传递给调用者的最佳方法是什么?

我的整体设置有点复杂,涉及混合的 c 和 c++ 代码,所以我包括一些背景信息:

我正在为 3D 引擎创建一个 c++ 库。该库旨在用于不同平台上的主机应用程序。

出于简单的兼容性原因,我现在打算将所有 c++ 代码隐藏在纯 c 中的 API 后面。到目前为止,这工作得很好。

我唯一不确定的是,这是通过我的 c API实际创建引擎实例的最佳方式。

我的第一种方法是:

// in myEngineAPI.h
void myEngineCreate(void * myEngine);
void myEngineRelease(void * myEngine);


// in myEngineAPI.cpp
#include "myEngineAPI.h"
#include "myPrivateCppEngine.h"

void myEngineCreate(void * myEngine) {
    myEngine = new Engine;               // <- this doesn't seem to work as expected
}
void myEngineRelease(void * myEngine) {
    delete ((Engine *)myEngine);
}


// in my host application
#include "myEngineAPI.h"

void * myEngine = NULL;
myEngineCreate(myEngine);    // <- problem: myEngine is still NULL after this line.

// ...draw some fancy stuff...

myEngineRelease(myEngine);

我希望这myEngineCreate(void * myEngine)会将我新创建的对象的地址分配给myEngine. 但是函数返回后,myEngine仍然指向NULL。为什么?

现在我的第二种方法是:

// in myEngineAPI.h
void * myEngineCreate();
void myEngineRelease(void * myEngine);


// in myEngineAPI.cpp
#include "myEngineAPI.h"
#include "myPrivateCppEngine.h"

void * myEngineCreate() {
    return new Engine;               // <- ok, the function returns a valid pointer
}
void myEngineRelease(void * myEngine) {
    delete ((Engine *)myEngine);
}


// in my host application
#include "myEngineAPI.h"

void * myEngine = myEngineCreate();  // <- yay, I have a void pointer to my engine

// ...draw some fancy stuff...

myEngineRelease(myEngine);

这行得通。myEngineCreate()给我一个指向我的引擎实例的不透明指针,我可以在随后的绘图调用中使用它,也可以将它交给我的释放函数,当我完成它时清理内存。这种方法的问题是,我的分析器抱怨myEngineCreate(). 我知道在一个地方创建一个对象并在另一个地方拥有它是一件微妙的事情,我似乎在这里做错了什么 - 但是什么?

提前感谢您的任何建议或帮助。

4

3 回答 3

9

让我们来看看你的myEngineCreate功能:

void myEngineCreate(void * myEngine) {
    myEngine = new Engine;
}

这不起作用,因为myEngine它是函数范围内的局部变量myEngineCreate。要在 C 中“通过引用”传递指针,您必须将其作为指向指针的指针传递,并使用 derefernece 运算符分配给指针:

void myEngineCreate(void ** myEngine) {
    *reinterpret_cast<Engine**>(myEngine) = new Engine;
}

&您可以使用指针的地址运算符来调用它:

void * myEngine;
myEngineCreate(&myEngine);

作为后期的附录,另一种可能的解决方案是返回新指针:

void* myEngineCreate() {
    retur reinterpret_cast<void*>(new Engine);
}
于 2013-03-14T12:19:28.937 回答
2

在 ac 函数中创建新对象并将对该新对象的一些引用传递给调用者的最佳方法是什么?

在 C 中,最好的、面向对象的方法是创建一个不复杂类型的对象,也称为不透明类型(void 指针不是不透明类型,它只是一个原始地址)。

例子:

// 引擎.h

typedef struct engine_t engine_t;

engine_t* engine_create (void);

// 引擎.c

struct engine_t
{
  /* all variables placed here will have true private encapsulation */
};


engine_t* engine_create (void)
{
  return malloc(sizeof(engine_t));
}

// main.c

int main()
{
  engine_t* my_engine = engine_create();
}

这是 C 中真正的面向对象,在没有 C++ 语言支持的情况下可以实现的最佳 OO。调用者将无法访问该结构的任何成员。

但是函数返回后,myEngine 仍然指向 NULL。为什么?

因为指针本身在 C 和 C++ 中是按值传递的。您要么必须传递指针的地址,要么将指针返回给调用者。可以在 SO 上轻松找到有关此主题的多个问题和常见问题解答。

于 2013-03-14T12:25:11.130 回答
1

我使用不透明指针做了类似的事情:

typedef struct my_c_engine *myCEngine;

extern "C" myCEngine createEngine() {
    return reinterpret_cast<myCEngine>(new myRealEngineClass());
}

extern "C" void releaseEngine(myCEngine c) {
    if(c) {
        myRealEngineClass *x = reinterpret_cast<myRealEngineClass*>(c);
        delete x;
    }
}

我这样做是因为我希望 C 部分完全隔离。

于 2013-03-14T12:22:10.643 回答