从D调用C++

Big*_*ion 16 c++ d

我已经阅读了解释如何从D解释C++的文档:http://dlang.org/cpp_interface.html.然而,有一些事情对我来说并不十分清楚.

以D网站上提供的示例为例:

#include <iostream>

using namespace std;

class D {
   public:
   virtual int bar(int i, int j, int k)
   {
       cout << "i = " << i << endl;
       cout << "j = " << j << endl;
       cout << "k = " << k << endl;
       return 8;
   }
};

D *getD() {
   D *d = new D();
   return d;
}
Run Code Online (Sandbox Code Playgroud)

然后可以从D调用C++类,如下所示:

extern (C++) {
    interface D {
        int bar(int i, int j, int k);
    }

    D getD();
}

void main() {
   D d = getD();
   d.bar(9,10,11);
}
Run Code Online (Sandbox Code Playgroud)

我不太清楚的是C++对象是如何被删除的.D垃圾收集器是否在C++对象上调用delete或者我们是否需要提供一个"删除器"函数来删除对象并从D中手动调用它?在我看来,如果我向C++类添加析构函数,它永远不会被调用.另外我注意到C++类必须以与D接口中声明的顺序完全相同的顺序声明成员函数(例如,如果我在bar()方法之前添加析构函数,则无法从D调用C++对象,但是如果在bar()方法之后声明析构函数,一切正常).

如果D接口定义为:

extern(C++){
   interface D{
       int bar();
       int foo();
   }
}
Run Code Online (Sandbox Code Playgroud)

对应的C++类由下式给出:

class D{
public:
   virtual int bar(){};
   virtual int foo(){};

};
Run Code Online (Sandbox Code Playgroud)

如何保证将以与D接口中声明的方法相同的顺序创建C++虚拟方法vtbl.对我来说,这并不能保证.换句话说,我们如何确定D :: bar()将位于vtbl的第一个位置?这不是实现/编译器依赖吗?

Aar*_*ron 7

我不希望D的垃圾收集器知道如何释放C++对象.这意味着(至少)D运行时:

  1. 对C++运行时做出假设,即如何删除C++对象
  2. 其他C++代码不再需要该对象

我相信你必须提供另一个调用传递给它的对象的C++函数.实际上,许多C++库(即使也是从C++中使用的)在从库内部调用构造函数的情况下也具有相同的模式.即使在直接的C中,在一个dll/exe中分配内存并在另一个中释放它通常是个坏主意.如果两个二进制文件不共享相同的运行时库,则可能会严重破坏.


Ada*_*ppe 4

其实现的具体方式是D对象简单地有一个C++兼容的vtable。因此,只有虚拟函数才起作用,并且由于表是按索引布局的,因此它们必须以相同的顺序出现。

D 不知道 C++ 构造函数、析构函数或任何其他特殊方法,但如果它们是虚拟的,它可能会抛出 vtable。

我现在编写了一个名为 dtoh waiting review 的快速小程序,它可以帮助从 D 源代码自动生成 C++ 头文件,以保持简单。它还没有完成,但无论如何它可能会有所帮助: https://github.com/adamdruppe/tools/blob/7d077b26d991dd5705e834900f66bea737a233b2/dtoh.d

首先编译它,dmd dtoh.d然后从 D 文件中生成 JSON:,dmd -X yourfile.d然后运行dtoh yourfile.json,它应该会输出一个可用的 yourfile.h。但就像我说的,它还没有完成,仍在等待整体设计的审查,所以它可能会很糟糕。不过,你总是可以做你现在正在做的事情,并且自己做。

无论如何,D 中看到的对象就像 C++ 中的 Class* 一样。您始终通过指针传递它,因此不会进行任何构造或复制构造。

D 和 C++ 也不理解彼此的内存分配系统。我遵循的规则是你的图书馆创建的任何东西,你的图书馆都应该能够销毁。因此,如果您的 C++ 程序新增了它,请确保它也在 C++ 中删除。您在 D 中创建的用于传递给 C++ 的任何对象也应该由 D 销毁...并且您可能需要手动执行此操作。如果您的 C++ 函数保留对 D 对象的引用,但 D 中没有引用,则它可能会被垃圾收集!因此,您要么要确保在对象的生命周期内 D 中始终有一个活动引用,要么使用 malloc 和 free 等函数自己创建一个销毁对象。

我不喜欢让调用者使用通用的 free(),因为版本不一定匹配。我说总是提供一种从你的图书馆获取免费东西的方法。即使它的实现只是 free(ptr);,给出您自己的函数也会明确表明应该使用它,并为您提供防止此类不匹配的保护。