简述D语言对C++的改良

说是改良,不过C++的死忠份子可能认为是对C++的亵渎,随便怎么说,就说是不一样的地方吧。

最近D语言没什么大动作,我又参与到xruby的builtin开发中,圈子里有点冷清。有留言说这里没什么人关注,的确是这样,抽点时间来写个简单的比较。

这里有一份各种语言的比较,大致可以了解D语言要对C++改些什么。
http://digitalmars.com/d/comparison.html

下面没什么顺序,想到什么就先列出来,可能随时扩充。

[b]1、内存管理。[/b]

内存管理在C++中非常难以掌握,大多数C++程序员没有写过内存管理程序,多数C++程序中存在内存问题,C++程序员终其一生都在与内存管理做斗争(有点过了。。)。

内存管理这么困难和重要,为何不彻底解决呢?垃圾收集是许多语言支持的一种内存管理方式,从语言级别上支持垃圾收集,你只需要分配,不需要释放。多数java程序员终其一生无法搞挂java虚拟机,对C++程序员来说把自己的程序搞挂是小儿科。

D语言也支持垃圾回收,不过为了照顾C++程序员对在堆栈上分配对象的喜好,它也支持这种方式。

[code]
import std.stdio;

class Test{
public:
this(){writefln("constructor");}
~this(){writefln("destructor");}
}

void main(){
writefln("start");
{
auto Test t = new Test; # LINE A
}
writefln("end");
}
[/code]

上面这段代码,在#LINE A处分配了一个Test对象,当退出它的作用域后,它的析构函数将被调用。注意这一行的auto关键字。

你也可以定义一个普通的对象,在退出作用域时调用delete来显示析构它。当然在复杂逻辑中,这个不太好控制,比如下面这段代码:
[code]
void foo(boolean flag){
Test t = new Test;
if (flag) return;
delete t;
}
[/code]
如果flag值为true,直接return了,可能与你的期望并不一致。D语言支持另一个关键字:
void foo(boolean flag){
Test t = new Test;
scope(exit) delete t;
if (flag) return;
}
scope(exit)声明了退出此作用域时要执行的代码,现在没有这个问题了,无论你后面有多少个可能return的分支。scope有更精细的控制,scope(success)和scope(failure)分别在正常退出作用域和出现异常时执行。

scope guard准确说是为了资源管理(RAII)而实现的,并不只是为了内存管理。对RAII的支持还可以使用auto关键字,把一个类声明为auto,就只能使用auto方式定义变量。

[b]2、委托。[/b]

委托也不是新东西,在脚本语言中应该是早就出现了吧,C#也支持委托。C++并不支持委托,仅仅从C那里借了个函数指针,稍稍做了点修改做成成员函数指针。不过这个东东并不好用,除了要面对怪异的语法以外,使用它也不方便。

委托的本质是一个对象指针和一个函数指针的绑定,为什么在C++中实现却如何艰难?原因就是C++支持的多继承,以及各种编译器实现上的差异,有兴趣的搜索一下“成员函数指针与高性能的C++委托”。

D语言分别实现了函数指针类型和委托类型,全局函数和声明为extern(C)的函数的指针就是这种类型;委托类型则是D对象的成员函数指针,注意是对象的不是类的,类方法取指针依旧是函数指针类型,因为它没有绑定对象;内嵌函数的指针也是委托类型。

D语言的委托是对象指针和函数指针的简单结合,你可以使用hack手段来增强它。(见这一篇: http://dlang.iteye.com/group/blog/26618 )

[b]3、单元测试[/b]

单元测试最好是写在实现代码附近,方便及时修改对照,D语言使用unittest关键字来支持它。

你可以在代码的任意位置使用unittest来标明单元测试代码,并使用assert来编写测试代码,在编译器命令行上加-unittest就可以编译出含有单元测试代码的程序。正式的应用可能不会这么简陋,要实现出单元测试类,捕获AssertError异常,否则每一个异常就中断了测试可没什么价值。

[b]4、契约编程[/b]

D语言的方法不仅有函数体,还可以加入2个附加的in和out代码块,这时原来的函数体要用body来标识:

[code]
int foo(int bar)
in{
assert(bar >= 0);
assert(bar <= 255);
}
out(result){
assert(result == 0);
}
body{
return bar % 2;
}

void main(){
foo(30);
foo(-2);
foo(256);
foo(31);
}
[/code]

代码应该不难看懂,in和out分别是分别标明前置条件(preconditions)检查和后置条件(postconditions)检查,还有一个不变量检查,只能用在结构、联合、类中:
[code]
import std.stdio;

class Foo{
private:
int value = 0;
invariant{
writefln("check");
assert(value == 0);
}

public:
void foo(){
writefln("in");
value = 1;
writefln("out");
}
}

void main(){
Foo foo = new Foo;
foo.foo();
}
[/code]

invariant会在每个public方法调用前后执行,输出如下:

[code]
check
in
out
check
Error: AssertError Failure tt(8)
[/code]

D目前不能打印出异常堆栈,提示信息有点差。

[b]5、同步原语[/b]

这在D语言里就是synchronized关键字:

[code]
import std.stdio;
import std.thread;
import std.c.time;

class PrintThread : Thread {
public:
int run(){
synchronized {
writefln("Thread start");
usleep(100000);
writefln("Thread end");
}
return 0;
}
}

void main(){
PrintThread[] threads = new PrintThread[10];
for (int i=0; i<10; ++i){
threads[i] = new PrintThread;
threads[i].start();
}
usleep(1100000);
}
[/code]

也可以synchronized(object),和java差不多。

6、COM接口兼容

通过使用extern(Windows)声明,D接口可以和COM接口二进制兼容。不多说了,看这篇: http://qiezi.iteye.com/admin/show/26681


-----------
先整这么多,有时间补充,毛糙了点,多多包涵。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值