06月28, 2009

Java程序中引入JRuby

以前有篇文章是写给Delphi程序增加对Pax JavaScript的支持 今天研究了一下给Java程序增加对 Ruby 的支持

目前可以通过 Apache的 BSF(Bean Script Framework) 和Sun的 Java Scripting(javax.script)

阅读全文 »

11月28, 2008

再学php

初学php是在大三。在看了STL,Ruby,JavaScript之后,再看php和当初完全是两种感觉了。

Array, Hash是动态语言中核心的数据结构。一旦你用过他们,你就会试图在此后接触的语言中寻找他们的身影或替代品。

阅读全文 »

10月04, 2008

构造函数中抛出异常会发生什么?

曾有人问了我个问题:如果在构造函数中抛出异常会怎么样?

现在可以回答了。

构造函数中抛出异常的主要问题是:当有多个资源分配时,如果出现异常,如何释放已经成功分配的资源。

下面是TCPL中推荐的一种方法:基本思想是将资源封装在对象中,然后将该对象以成员变量的形式聚合入你的类中。这个封装类在其析构函数中释放资源。这样,当你的类的构造函数中出现异常后,编译器会调用封装类的对象的析构函数,释放资源。

阅读全文 »

05月12, 2008

C++设计模式的新形式

最近再看WTL。C++模板带来的设计模式实现的改变,的确没那么容易很快接受。慢慢来吧。

上面是一个实验:一个采用继承实现多态,另一个采用模板实现的多态。 前者称为动多态(Dynamic Polymorphism),后者称为静多态(Static Polymorphism)

下面是汇编代码上的差别,静多态没有使用虚函数,所以代码要少一些。

动多态Imple* impl所指类型是在运行期时确定的,上图中多出的代码就是通过虚函数表查找合适的函数指针。静多态的这个确定过程是在编译期完成的。编译器会用模板参数(TA,TB)代替Impl,从而生成的代码直接指向被调用的函数,也没有虚函数表的查找过程。

从类图上来看,静多态是平面的,不像动多态有继承层次。这也是习惯了OO思想后不容易理解的。

阅读全文 »

05月02, 2008

又见虚函数

前几天我的一个同学在IBM笔试中遇到一道C++题,大概意思就是:

#include <stdio.h>
class Base {
    virtual void f(int i){printf("Base");}
};
class Derive { //补充!注意,这里没有继承Base
public:
    virtual void f(int i){printf("Derive");}
};

int main(int,char**)
{
    Derive* pd = (Derive*)new Base;
    pd->f(1);
    return 0;
}

What is the output?

要是将Base中的f(int i)改成 anything(int i)就更有难度了。

#include <stdio.h>
class Base {
  virtual void func(int i) { printf("base!!!\n"); }
  virtual void f(int i) { printf("base..."); }
};
class Derive {
 public:
  virtual void f(int i) { printf("derive..."); }
  virtual void func1(int i) { printf("derive!!!\n"); }
};
int main() {
  Base b, *pb;
  Derive d, *pd;
  pd = (Derive *)new Base;
  pd->func1(1);
  return 0;
}

输出:Base...

编译器只是取出对象的vftable然后找到虚函数表首地址,然后“偏移”,然后调用。 根本不管调用函数的名字、参数列表和访问权限。如果恰巧参数列表中的参数在栈中的大小一样,那就成功调用了,如果不一样,就会出现运行时错误(检查堆栈时报错)

阅读全文 »

09月19, 2007

c++陷阱之临时变量

先看代码:

我们开始都会认为在调用Say()之后,对象d的m_b成员变量会被修改为7但是结果却输出“1”,原因如下:

50,51行处出现了一个$T563,这其实是一个C++生成的临时对象汇编代码

37,38行如下:

37 _d$ = -8      
38 $T563 = -12
( sizeof(Derived)==8, sizeof(Base)==4 )

上面

mov eax,DWORD PTR _d$[ebp]
mov DWORD PTR $T563[ebp],eax

这段代码是将对象d的内容拷贝到临时变量中,并且只拷贝Base中有的部分,这样做 就是所谓的“Slicing”。有些书中说这一步是由拷贝构造函数完成的。概念上是这样的, 但是实际上,编译器并没有生成一个真正意义上的拷贝构造函数。

这更进一步说明C++产生了一个临时对象作为强制转换的中间结果。然后以这个临时 对象代替我们的对象d,来调用函数Say()。那么结果自然是,临时变量的m_b被改变, 而我们的d.m_b没有发生变化

这种强制类型转换就是所谓的"向上转型",upcasting。 也叫Object Slicing。这种操作应该避免使用

阅读全文 »