生如夏花之绚烂

 
 

Powered by: 博客园
模板提供:沪江博客
博客园 | 首页 | 发新随笔 | 发新文章 | 联系 | 订阅订阅 | 管理

2012年5月9日

delphi 接口 对象 交叉引用

在delphi编程中有时会遇到类A,类B相互引用或者一方引用另一方的问题。这种问题无外乎以下几种做法。

1.很多人可能都用过的,delphi下有两个地方可以uses其他单元,假如类A,类B在不同的单元UnitA, UnitB且互相引用。一般UnitA interface uses UnitB; UnitB implementation UnitA,这样就可以了,不能同时在interface或implementation中互相引用,否则编译不过。这样虽然达到了目的,代码的耦合度非常高。

2.在其中一个定义函数原型,然后公布出来,让另一个实现。比如类A包含了类B(可以自由使用类B得可见接口),而类B想使用类A得接口,而UnitB是没有引用UnitA的,那么UnitB根本不知道有类A,如果对类B是少量的调用,可以在UnitB定义一些函数原型,然后类A实现这种原型的函数并将地址赋值给类B,这样类B可以调用自己的函数指正,无须知道A的情况。但若类B需要用到类A较多的接口时,这样做相当麻烦。

3.使用delphi的接口。delphi的接口比较像c++的头文件。他定义的只是一套规则,实现的类必须严格依照规则,把办法交给了实现者,而不是调用者。这里类A将那些需要提供给其他类使用的方法做成一个interface,加入在单元UnitIA,接口名为IA,类A实现IA。类B引用UnitIA单元并定义外部可见的IA类型成员变量。类A在生成类B时将接口赋予类B,类就可以正常的调用类A得方法。类B在释放自己时必须先释放自己的成员变量类A,但由于接口的引用计数问题,编译器发现类B得引用计数不为0,触发异常,不予释放。假如释放过程成功,在释放类B得变量时由于导致类A得计数为0,将导致类A的实例被自动释放,继续执行类A得析构函数必定异常。

IAIntf = interface
['{37BFA0BF-4952-47F8-AAB8-8FAAD36B0EE5}']
procedure test;
end;

// B通过接口引用A
TB = class
private
FIA: IAIntf; // A的接口
public

property IA: IAIntf read FIA write FIA;
end;

// B为A的成员变量, 此类给外部使用,
TA = class(TInterfacedObject, IAIntf)
private
FB: TB;
public
constructor Create;
destructor Destroy; override;

procedure test;
end;

 

//-----------------------------------------1----------------

var

  A: TA;

begin

   // 这样必定出错

  A := TA.Create;  // 此时A已被FB引用了一次

  //A.FB.IA := nil;  // 这样解除引用导致A被编译器释放(A.Destroy),下面的A.Free将触发异常

  A.Free;              // 由于BeforeDestruction判断RefCount<>0导致异常。

end;

 

//------------------------------------2-----------------------------

var

  A: TA;

  IA: AIntf;

begin

  // 这种是可行的,声明A是为了看引用计数,可以构造后自己赋值给IA

  A := TA.Create;  // 此时A已被FB引用了一次

  IA := A;        // A被引用二次

  A.FB.IA := nil;  // 将FB对A的引用解除,RefCount=1

  IA := nil;   // A的引用计数再次-1,编译器自动释放A

  // 到这里对象A已经被释放,不能再A.Free。或者上面的IA := nil不要也可以释放。

end;

posted @ 2012-05-09 16:09 生如夏花之绚烂 阅读(219) 评论(0) 编辑
 

2012年4月14日

建立不规则窗口

procedure RgnWindow();

begin

var
  rgn1,rgn2: HRGN;
  x,y,w,h, i: Integer;
begin
w := img1.Width;
h := img1.Height;

rgn1 := CreateRectRgn(0, 0, w, h);

for x := 0 to w - 1 do

begin
  for y := 0 to h - 1 do

  begin
    if img1.Canvas.Pixels[x,y] = clwhite then
    begin
      rgn2 := CreateRectRgn(x, y, x+1, y+1);
      CombineRgn(rgn1, rgn1, rgn2, RGN_XOR);
      DeleteObject(rgn2);
    end;

  end;

end;
SetWindowRgn(Handle, rgn1, True);

Self.Width := w;
Self.Height := h;

end;

Img1为TImage控件。

根据图片的形状建立窗口。

posted @ 2012-04-14 13:41 生如夏花之绚烂 阅读(5) 评论(0) 编辑
 

2012年4月12日

Navicat 10.0.10 for mysql 注册码

Name: Life404

Org: Life404.cn

Key: NAVD-IO5R-4VGM-TIZD 
       NAVL-RK72-URYA-CINR

 

第一个Key试过,还未过期可以使用。

posted @ 2012-04-12 14:12 生如夏花之绚烂 阅读(20) 评论(0) 编辑
 

2012年3月15日

Delphi WebService Variant 多个

     在delphi的webservice技术中有种奇怪的现象,如果你一个做数据提交用的webservice接口有多个Variant参数,delphi环境会报'Invalid variant type',但如果是个读取数据的接口中有多个Variant参数是不会有问题的。这个问题因工作忙我目前没有继续跟踪,只好采用了权宜之计,建立一个Variant数组,这样多个Variant做一个参数打包提交,这样是没有问题的。

     注:delphi做dcom时没有这种问题。

posted @ 2012-03-15 09:55 生如夏花之绚烂 阅读(16) 评论(0) 编辑
 

2012年3月6日

编码、模块化、接口

     本文主要写自己在功能模块设计及编码时一些习惯。

     在面向对象的编程时我一般喜欢在一个文件中实现一个类,除非这个类的代码量非常的小而且简单,暂且把这个类也就叫着一个模块,毕竟模块可大可小,一个具备一定功能的类完全可以称为一个模块。既然他是模块就会设计到和其他模块的互相调用关系,我一直认为模块功能要清晰化,属于此模块的功能如果要提供给其他模块使用一定要公布API,而不能将数据直接暴露。如果出现了本模块需要调用的功能而又无法确定实现方式的,一般可以定义函数原型(暂且叫接口)然后公布这个原型,应用者只要将实现函数指针注册进来,然后本模块即可调用(系统的callback function也是这个意思)。

     在一个系统中会存在很多的功能模块,他们需要配合完成一些系统功能。结构上模块应该形成树状,就像一个父类可以派生多个子类,子类又可派生子类。应避免上下层模块互相调用,上层包含模块可以通过下层模块的接口调用下层模块,下层模块应该通过回调的方式调用上层模块的功能(这样避免下层再包含上层模块),或者这个实现可能是同层的其他模块,都可以通过上层模块牵线搭桥达到效果。这样形成的结构总是上次对下层的包含,模块层次上结构清晰,利于代码的阅读和维护。

posted @ 2012-03-06 23:22 生如夏花之绚烂 阅读(4) 评论(0) 编辑
 

2012年2月18日

free pascal、Lazarus
摘要: free pascal是一个pascal语言编译器。可以用于编译win32下pascal开发程序。类似于delphi的编译器。如果在delphi下写的是标识的pascal代码是可以在free pascal下编译的。free pascal是跨平台的,这样可以实现交叉编译,一次书写多次编译即可。Lazarus是以编译器free pascal为基础的Pascal语言的整合开发环境(IDE),和Delphi高度兼容,被视作后者的开源替代品。目前已有中文界面。支持的系统有Linux,Win32和FreeBSD,Mac OS。s阅读全文
posted @ 2012-02-18 23:15 生如夏花之绚烂 阅读(11) 评论(0) 编辑
 
com概念
摘要: com(component object model)组件对象模型。 com是Microsoft的一项技术,可以实现代码的二进制重用,可以跨进程、机器或者网络,目前只支持Microsoft的系统和Apple Mac操作系统。COM的应用非常广泛,Microsoft的系统底层到处是com的身影,比如DirectX。二进制重用体现在,我们更新一个新的com组件是不需要将整个程序重新编译,只需要更新com组件即可。这样可以保证老的逻辑是不会的,不会因为更新引发新的问题。com组件的实现不受语言限制,遵守com规范的语言都可以写com组件。 com组件的存在形式可以多样,可以是in process如.阅读全文
posted @ 2012-02-18 23:03 生如夏花之绚烂 阅读(13) 评论(0) 编辑
 

2012年2月13日

异步、同步
摘要: 异步(asynchronous)和同步(synchronous),从字面上可以理解为一个事情处理顺序的问题。同步就是下一步计划必须等待上一步完成,否则不能做其他事情;异步就是下一步计划可以不用等待上一步完成,可以先去做别的事情,然后在某个未知的时刻再回到上一步完成的地方继续工作。 同步与异步概念可以说是无处不在,不管是生活中还是计算机领域,只是我们平时在生活中没有留意这个问题。在计算机的理论学习中应该经常会碰到这个概念的,比如硬件方面的(硬件一般都是异步的,比如I/O),然后上升到软件方面的。硬件方面比如快、慢速设备的配合上,软件方面也有很多的例子,比如Win32 API下的消息发送函...阅读全文
posted @ 2012-02-13 18:02 生如夏花之绚烂 阅读(15) 评论(0) 编辑
 

2012年2月10日

变量命名法则
摘要: 匈牙利命名法:bBusy: 布尔型cApples: 项目计数dwLightYears: 双字(系统)fBusy: 布尔型(标记)nSize: 整型(系统)或计数(应用程序)iSize: 整型(系统)或索引(应用程序)fpPrice: 浮点数dbPi: 双精度浮点数(系统)pFoo: 指针rgStudents: 数组或范围szLastName: 零结束字符串u32Identifier: 无符号32位整型(系统)stTime: 时钟结构fnFunction: 函数名对于指针和数组来说,它们实际上并不是数据类型,因此通常在助记符后面跟着实际元素的类型。pszOwner: 指向零结束字符串的指针rgf阅读全文
posted @ 2012-02-10 12:20 生如夏花之绚烂 阅读(15) 评论(0) 编辑
 

2012年1月11日

记录我常使用的代码文件描述方式
摘要: {************************************************************************ * -------如果此文件内容涉及到版权问题,在此处醒目说明,比如转义了别人的头文件-------- * FileName : 文件名 * Version : 版本 * Description : 对此文件的描述 * Author : 文件作者 * Created : 建立日期 * History : 以下开始记录修改历史 * 1.Date : 第一次修改时间 * Author : 作者 * Modify...阅读全文
posted @ 2012-01-11 14:32 生如夏花之绚烂 阅读(13) 评论(0) 编辑
 
仅列出标题  下一页