《delphi高手突破》节选二——构造函数与异常 (100分)

  • 主题发起人 主题发起人 Nicrosoft
  • 开始时间 开始时间
N

Nicrosoft

Unregistered / Unconfirmed
GUEST, unregistred user!
呵呵,终于赶在春节前完成了书的第三章(异常及错误处理),在此再贴出节选。呵呵。
前两章节选在此:
第一章(全文)http://www.delphibbs.com/delphibbs/dispq.asp?lid=851520
第二章(节选)http://www.delphibbs.com/delphibbs/dispq.asp?lid=904634
构造函数与异常
这个话题在C++社区中经常会被提起,而在Delphi社区中似乎从来没有人注意过。也许由
于语言的特性,使得Delphi程序员不必关心这个问题。但我想Delphi程序员也应该对该问
题有所了解,知道语言为我们提供了什么而使得我们如此轻松,不必理会它。正所谓“身
在福中须知福”。
我们知道,类的构造函数是没有返回值的,如果构造函数构造对象失败,不可能依靠返回
错误代码。那么,在程序中如何标识构造函数的失败呢?最“标准”的方法就是:抛出一
个异常。
构造函数失败,意味着对象的构造失败,那么抛出异常之后,这个“半死不活”的对象会
被如何处理呢?
在此,我想读着有必要先对C++对这种情况的处理方式先有个了解。
在C++中,构造函数抛出异常后,析构函数不会被调用。这种做法是合理的,因为此时对
象并没有被完整构造。
如果构造函数已经做了一些诸如分配内存、打开文件等操作的话,那么C++类需要有自己
的成员来记住做过哪些动作。当然,这样做对于类的实现者来说非常麻烦,因此一般C++
类的实现者都避免在构造函数中抛出异常(可以提供一个诸如Init和UnInit的成员函数,
由构造函数或类的客户去调用它们,以处理初始化失败的情况)。而每一本C++的经典著
作所提供的方案是使用智能指针(STL的标准类auto_ptr)。
在Object Pascal中,这个问题变得非常的简单,程序员不必为此大费周折。如果Object
Pascal的类在构造函数中抛出异常,编译器会自动调用类的析构函数(由于析构函数不允
许被重载,可以保证只有唯一一个析构函数,因此编译器不会迷惑于多个析构函数之中)。
析构函数中一般会析构成员对象,而Free()方法保证了不会对nil对象(即尚未被创建的
成员对象)调用析构函数,因此在使得代码简洁优美的前提下,又保证了安全。
type MyClass = class
private
FStr : PChar;
// 字符串指针
public
constructor Create();
destructor Destroy();
override;
end;

constructor MyClass.Create();
begin
FStr := StrAlloc(10);
// 构造函数中为字符串指针分配内存
StrCopy(FStr, 'ABCDEFGHI');
raise Exception.Create('error');
// 抛出异常,没有理由,呵呵
end;

destructor A.Destroy();
begin
StrDispose(FStr);
// 析构函数中释放内存
WriteLn('Free Resource');
end;

var
Obj : TMyClass;
i : integer;
begin
try
Obj := TMyClass.Create();
Obj.Free();
WriteLn('Succeeded');
except
Obj := nil;
WriteLn('Failed');
end;

Read(i);
// 暂停屏幕,以便观察运行结果
end.

在这段代码中,构造函数抛出异常,执行的结果是:
Free Resource
Failed
此时的“Free Resource”输出是由编译器自动调用析构函数所产生的。
因此,如果类的说明文档或类的作者告知你,类的构造函数可能会抛出异常,那就要记
得用try…except包住它!
C++与Object Pascal对于构造函数抛出异常后的不同处理方式,其实正是两种语言的设
计思想的体现。C++秉承C的风格,注重效率,一切交给程序员来掌握,编译器不作多余
动作。Object Pascal继承Pascal的风格,注重程序的美学意义,编译器帮助程序员完成
复杂的工作。
 
不知道你要干什么,我先收藏起来
 
大哥的帖子以前好象发过的。
 
to 吴剑明:
是的,不过不一样。这个段落正是我以前的一片文章改编的。
 
老大,书什么时候正式出版呀?
 
add to favorite
 
等待你的书~
 
这篇文章有点眼熟。
 
广西人悬红取刘海洋和它母亲,活人60万,死人20万,要求见人头
详谈联系:entrant@163.net
发出去
 
what's mean?????????[?]
 
在Csdn上见多了
 
是的,我在CSDN上贴过
 
现在开始存钱
 
To Nicrosoft:
您的文章中有不少笔误。如
type MyClass = class
应该为type TMyClass = class,
constructor MyClass.Create();
应该为 constructor TMyClass.Create();
destructor A.Destroy();
A是什么?应该是TMyClass吧?
我希望书中不要出现这些笔误,否则就大煞风景了。
另外请教Nicrosoft:
我编译了您上面的代码,我故意在
destructor Destroy();
override;后加了个
destructor Destroy(var I:integer);
overload;
定义为:
destructor TMyClass.Destroy(var I:integer);
begin
WriteLn('Overload?');
end;
您说析构函数不允许被重载,可是我重载了析构函数,编译器仅仅给出了警告信息而已。这是怎么回事?还望大侠教我!
 
楼上的哥们给人家点面子吗?
(不过挺佩服你的,你nb)
 
to Bahl:谢谢,书里是没有这样的笔误的,呵呵。
我想您定义:destructor Destroy(var I:integer);
overload;
虽然能通过编译,不过,由于TObject.Free()方法只会调用派生类destroy()方法,如果没
有,则调用的是TObject.Destroy(这是一个空方法)。
因此,你重载(overload)析构函数,是没有什么具体意义的,也不符合“标准”做法。
 
后退
顶部