2013-12-09 57 views
4

D有一个梦幻般的模块系统,与C++相比,它大大缩短了编译时间。根据文献,D仍然提供了不透明的结构和联合体,以便实现这个pimpl习语。我的问题是:我怎样才能在一个模块中声明一个嵌套结构(或联合),并在另一个模块中定义它?这是什么语法?D编程语言中的Pimpl-idiom

在C++中的头看起来像这样

struct S { 
    ... 
    struct Impl; 
    Impl * p; 
}; 

和实现文件(CPP文件)会用一些有趣的前瞻性:: -syntax这样的:

#include "header.h" 
struct S::Impl { 
    ... 
}; 

我如何在D中实现相同?

回答

5

D(DMD,至少)使用.di文件进行声明。它们有点相当于C .h文件,但它们是可选的。 D编译器可以自动生成.di文件(当指定-H开关时),但我相信目前它所做的只是剥离函数体和单元测试。

下面是实现PIMPL一种方式使用.di文件:

  • mod.di

    struct S 
    { 
        struct I; 
        I* pi; 
    } 
    
  • mod.d

    struct S 
    { 
        struct I 
        { 
         int v; 
        } 
    
        I* pi; 
    } 
    

请注意,目前您有责任确保S中的字段在.d.di文件中都相同 - 如果它们不同,编译后的模块将不同地了解字段的布局方式,这可能导致内存损坏。当前的编译器实现不会验证.d.di文件中的定义是否匹配。

+0

这将是链接器的责任,以验证内存布局的假设,因为这是唯一知道所有这些 –

+0

我认为这是不正确的。数据结构不存储到目标文件。链接器不知道类型。 –

+0

但编译器不需要知道'.d'和'.di'文件 –

1

我的问题是:如何在一个模块中声明一个嵌套的结构(或联合)并在另一个模块中定义它?

为了得到它 - 这是故意不可能在D设计。这是拥有可靠模块系统的直接后果 - 每个符号声明都由其声明的模块名称隐含地限定。由于各种原因,您不能将符号劫持到另一个模块“命名空间”中。

这就是说,没有必要在同一模块中使用pimpl的方法。有关更多详细信息,请参阅Cyber​​Shadow答案。

1

另一种方法是基于D的系统类的层次上:

所有对象继承或明或暗地在对象

这样的想法是PIMPL实现在OuterClass,生成相应的 二档,手动从二档 删除OuterClassPrivate的所有定义和改变平普尔成员的声明。

例如:

共享库的第一版本

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 

然后编辑genereated二档:

// 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刚建成一个。运行测试应用程序不能崩溃,但输出会有所不同。