D具有一个出色的模块系统,与C ++相比,它可以大大缩短编译时间。根据文档,D仍然提供不透明的结构和联合,以便启用pimpl习语。我的问题是:如何在一个模块中声明嵌套结构(或联合)并在另一个模块中定义它?那是什么语法?
在C ++中,标题看起来像这样
struct S {
...
struct Impl;
Impl * p;
};
并且实现文件(cpp-file)将使用一些有趣的::
语法,如下所示:
#include "header.h"
struct S::Impl {
...
};
如何在D中实现相同的功能?
答案 0 :(得分:5)
D(至少DMD)使用.di
个文件进行声明。它们有点等同于C .h
文件,但它们是可选的。 D编译器可以自动生成.di
个文件(当指定-H
开关时),尽管我认为它目前所做的只是剥离函数体和单元测试。
以下是使用.di
文件实现PImpl的一种方法:
mod.di
:
struct S
{
struct I;
I* pi;
}
mod.d
:
struct S
{
struct I
{
int v;
}
I* pi;
}
请注意,目前您有责任确保S
和.d
文件中.di
中的字段相同 - 如果它们不同,则已编译的模块将具有关于如何布置字段的不同知识,这可能导致内存损坏。当前的编译器实现不会验证.d
和.di
文件中的定义是否匹配。
答案 1 :(得分:1)
我的问题是:如何在一个模块中声明嵌套结构(或联合)并在另一个模块中定义它?
为了得到它直接 - 在设计中故意不可能在D中。这是拥有一个可靠的模块系统的直接结果 - 每个符号声明都由它在里面声明的模块名称隐式限定。由于各种原因,您无法将符号劫持到另一个模块“命名空间”。
也就是说,没有必要在同一个模块中使用 pimpl 方法。您可以参考 CyberShadow 答案了解更多详情。
答案 2 :(得分:1)
另一种方法是基于D类的层次结构系统:
所有对象显式或隐式地继承对象 。
所以想法是用pimpl实现OuterClass,生成相应的 di-file,从di-file手动删除OuterClassPrivate的所有定义 并更改pimpl-member的声明。
例如:
共享库的第一个版本
module pimpl.mylib;
class PimplTest
{
this()
{
mImpl = new PimplTestPrivate();
}
~this()
{
}
string sayWhat(string what)
{
return mImpl.ku ~ " " ~ what;
}
private class PimplTestPrivate
{
string ku = "Ku!!1";
}
private PimplTestPrivate mImpl;
}
测试应用程序:
module main;
import std.stdio;
import pimpl.mylib;
void main()
{
PimplTest t = new PimplTest();
writeln(t.sayWhat("?"));
}
共享mylib可以通过以下方式构建(在Linux下):
$ dmd -H -c mylib.d -fPIC
$ dmd -ofmylib.so mylib.o -shared -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/phobos/library/is
然后编辑生成的文件:
// D import file generated from 'mylib.d'
module pimpl.mylib;
class PimplTest
{
this();
~this();
string sayWhat(string what);
// NOTE this
private Object mImpl;
}
编译测试itsel
$ dmd -c main.d /path/to/first/version/of/mylib.di
$ ln -s /path/to/first/version/of/mylib.so .
$ dmd main.o -L-l:mylib.so -defaultlib=libphobos2.so -L-rpath=/path/to/where/shared/phobos/library/is:.
$ ./main
Say: ?
然后我们改变mylib:
module pimpl.mylib;
import std.conv;
class PimplTest
{
this()
{
mImpl = new PimplTestPrivate();
}
~this()
{
}
string sayWhat(string what)
{
return mImpl.getMessage1(mImpl.getValue(), what);
}
private class PimplTestPrivate
{
int getValue()
{
return 42;
}
string ku = "Ku!!1";
string getMessage1(int x, string y)
{
return "x = " ~ to!(string)(x) ~ ", " ~ y;
}
double pi = 22.0/7.0;
}
private PimplTestPrivate mImpl;
}
编译它并用刚构建的mylib替换第一版mylib的二进制共享对象(so文件)。运行测试应用程序不得崩溃,但输出将不同。