delphi 的虚方法和动态方法

落幕年代 2012-03-16 08:52:11
delphi 的虚方法 和 动态方法有什么区别吗?
请大侠门说说
delphi虚方法和动态方法有什么用?
一般什么时候用啊?
谢谢大家
...全文
303 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
落幕年代 2012-03-16
  • 打赏
  • 举报
回复
非常感谢 大家
现在对虚方法理解是: 当有子类要进行覆盖或继承时 就定义父类为虚方法;假如不定义虚方法呢?则父类和子类就调用各自的方法; 因此 虚方法 减少了代码的重写
不知道是这样理解的吗?
大侠门 可以说说 抽象方法吗? 如果不定义父类的抽象方法会怎样呢? 抽象方法有什么好处呢?
unicodestring 2012-03-16
  • 打赏
  • 举报
回复
李维的Inside VCL 深入核心VCL架构剖析
kaikai_kk 2012-03-16
  • 打赏
  • 举报
回复
简单的理解是:为了子类重用或者覆盖,扩展性更强

比如100个窗体,都是继续某一个窗体,但100个窗体中都有一个方法代码是一样的
就可以把此方法写在父窗体中,声明为virtual;或者dynamic;那么这100个子窗体就可以不写一行代码了
有一天某个子窗体要做改动时,用override就可以覆盖此方法,在自己的单元里重写此方法,很方便
s11ss 2012-03-16
  • 打赏
  • 举报
回复
RAD Studio

Virtual Methods

Expand AllVirtual methods employ a more complicated, and more flexible, dispatch mechanism than static methods. A virtual method can be redefined in descendant classes, but still be called in the ancestor class. The address of a virtual method isn't determined at compile time; instead, the object where the method is defined looks up the address at runtime.

To make a method virtual, add the directive virtual after the method declaration. The virtual directive creates an entry in the object's virtual method table, or VMT, which holds the addresses of all the virtual methods in an object type.

When you derive a new class from an existing one, the new class gets its own VMT, which includes all the entries from the ancestor's VMT plus any additional virtual methods declared in the new class.



-------------霸气的分割线-----------------

RAD Studio

Dynamic Methods

Dynamic methods are virtual methods with a slightly different dispatch mechanism. Because dynamic methods don't have entries in the object's virtual method table, they can reduce the amount of memory that objects consume. However, dispatching dynamic methods is somewhat slower than dispatching regular virtual methods. If a method is called frequently, or if its execution is time-critical, you should probably declare it as virtual rather than dynamic.

Objects must store the addresses of their dynamic methods. But instead of receiving entries in the virtual method table, dynamic methods are listed separately. The dynamic method list contains entries only for methods introduced or overridden by a particular class. (The virtual method table, in contrast, includes all of the object's virtual methods, both inherited and introduced.) Inherited dynamic methods are dispatched by searching each ancestor's dynamic method list, working backwards through the inheritance tree.

To make a method dynamic, add the directive dynamic after the method declaration.

武稀松 2012-03-16
  • 打赏
  • 举报
回复
虚方法表存在于每个派生类中.动态方法表只存在于实现该方法的类中.
虚方法调用是根据虚方法的偏移到表中直接调用.
动态方法则是在自己中找,没有就到父亲类中找,在没有就去爷爷那里找....

虚方法费空间但省时间.动态方法省空间但时间开销大.
如果是频繁调用的方法又不在乎一点点空间应该用虚方法.
如果是调用不多或者极端在意空间可以用动态方法.


不过对于触及使用者来说他们用法上没区别.
我看见佛 2012-03-16
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 tiankun66 的回复:]
方法来到类中, 以前的特点基本都在;
因为类一般是存在于一个继承链中, 所以就有了一些新的概念, 譬如: 继承、覆盖;
也有了很多新名称, 譬如: 静态方法、虚方法、动态方法、抽象方法、类方法、消息方法.

先从虚方法与动态方法开始吧


-------------------------------------------------------------------------……
[/Quote]个人感觉这里讲的挺清楚了。
我看见佛 2012-03-16
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 w001001001001 的回复:]
1楼的能讲清楚点吗,有相关的文章介绍吗?
[/Quote]delphi语法的书一般都有此类介绍
我看见佛 2012-03-16
  • 打赏
  • 举报
回复
关于虚方法:比如DELPHI中经常用到一一种情况是当你的窗口用到继承的时候,子窗体继承父窗体的方法,此时你在父窗口声明一个
procedure Test(Sender: TObject);virtual;的事件,然后你的子窗体可以通过
procedure Test(Sender: TObject);override;对父窗体的Test事件进行重写。
procedure Test(Sender: TObject);override;
begin
inherited;//子窗体的重写代码中加上这个则表示仍继承父窗体的Test事件,删除则表示不继承。
end;
大肚肥肥 2012-03-16
  • 打赏
  • 举报
回复
方法来到类中, 以前的特点基本都在;
因为类一般是存在于一个继承链中, 所以就有了一些新的概念, 譬如: 继承、覆盖;
也有了很多新名称, 譬如: 静态方法、虚方法、动态方法、抽象方法、类方法、消息方法.

先从虚方法与动态方法开始吧


--------------------------------------------------------------------------------

//下面的类中就定义了两个虚方法(virtual)、两个动态方法(dynamic)
TMyClass = class
procedure Proc1(x,y: Real); virtual;
function Fun1(x,y: Real): Real; virtual;
procedure Proc2(x,y: Real); dynamic;
function Fun2(x,y: Real): Real; dynamic;
end;
--------------------------------------------------------------------------------

//定义成虚方法或动态方法, 就意味着在后来的子类中将要被覆盖(override), 也就是重写
TBass = class
procedure Proc(x,y: Real); virtual;
function Fun(x,y: Real): Real; dynamic;
end;

TChild = class(TBass)
procedure Proc(x,y: Real); override;
function Fun(x,y: Real): Real; override;
end;

{正是因为这种机制而形成了多态}
--------------------------------------------------------------------------------

//那虚方法和动态方法有什么区别呢?
13.8px">
每个类都内含着两个表: 虚方法表(VMT)和动态方法表(DMT);
VMT 表包含着本类与其所有父类的虚方法 - 那一般会是一个比较庞大的表;
DMT 表只包含本类的动态方法 - 如果要调用其上层类的动态方法, 只能逐级查找;
因此, 使用虚方法速度上会有优势, 使用动态方法会节约内存;
在 Delphi 初期只有 virtual 而没有 dynamic ; 后来随着 VCL 日渐庞大, 才有了 dynamic ;
譬如类的事件方法一般都是在早期定义, 为了节约空间, 事件方法在 VCL 中基本都定义成了 dynamic ;
这样看来: virtual 和 dynamic 并没有太多区别, 一个侧重速度、一个节约空间; 它们是可以互相代替的!
另外: 因为它们区别不大, 并且是先有 virtual , 所以人们也习惯于把"虚方法"和"动态方法"都称作"虚方法".

以上来之万一的博客
Elvis_chen 2012-03-16
  • 打赏
  • 举报
回复
1楼的能讲清楚点吗,有相关的文章介绍吗?
wzwcn 2012-03-16
  • 打赏
  • 举报
回复
功能上没区别。但虚方法注重调用速度的优化,动态方法注重代码大小的优化。所以一般经常需要后代码覆盖的方法用虚方法,不经常的用动态方法
落幕年代 2012-03-16
  • 打赏
  • 举报
回复
恩 明白了 谢谢大家
yibeilee 2012-03-16
  • 打赏
  • 举报
回复
《面向对象编程思想》刘艺著
我觉得还不错,讲得比较清楚。
Inprise/Borland公司的Delphi可能是当前最好的Windows快速应用程序开发工具。 随着它在Linux平台上的版本Kylix的发布,它在Unix世界的前景也十分看好。Delphi完 全支持COM、ActiveX、可视化组件库(VCL),并提供了可扩展、可定制的快速应用程 序开发环境。本书是这种功能强大的开发工具的全面参考。 本书从简介Delphi Pascal并讨论Delphi对象模型开始,讨论了运行时类型信息 (RTTI)——Delphi开发环境的关键部分,这一点在Delphi的其他正式帮助文档中很 少论及。本书还用一章的篇幅讨论了Delphi中的并发编程,以及多线程应用程序的创建。 本书的主要内容是Delphi语言以字母顺序排列的完整参考。每项参考的内容都包括: 语法,使用标准编码惯例 说明参数列表,如果函数或过程包括参数的话提示和技巧—— 在实际程序中使用某个组件的实用信息一个简单的例子其他相关关键字的交叉参考本书 秉承“坚果”(In a Nutshell系列技术手册的一贯风格。不管你对Delphi的掌握程度如何, 本书都是你日常工作中不可或缺的标准参考指南。阅读本书,你将领略到Delphi的精华所在, 还可以解决实际编程中可能遇到的问题。 第一章 Delphi Pascal 单元 程序 库 包 数据类型 变量和常量 异常处理 文件1/O 函数和过程 第二章 Delphi对象模型 类和对象 接口 引用计算 消息 内存管理 旧式的对象类型 第三章 运行时类型信息 方法表 公布的声明 .TypInfo单元 方法动态方法 初始化和结束化 自动的方法 接口 探究RTTI 第四章 并发编程 线程和进程 TThread类 BeginThread和EndThread函数 线程局部存储 进程 未来化 第五章 语言参考 第六章 系统常量 Variant类型码 开放数组类型 方法表偏移值 运行时错误代码 第七章 运算符 一元运算符 多元运算符 附加运算符 比较运算符 第八章 编译器指示字 附录一 命令行工具 附录二 SysUtils单元 词汇表 多谢支持【Think you to your download~】
一共两个压缩分卷,这是第一个分卷 第一部分 模式编程原理 第1章 模式概述 1.1 模式的概念 1.1.1 什么是模式 1.1.2 模式可以做什么 1.2 模式与架构 1.2.1 什么是架构 1.2.2 架构和模式的关系 1.3 从面向对象编程到模式编程 1.3.1 关于封装的哲学 1.3.2 利用继承实现变化的封装和简单的复用 1.3.3 借助模式封装多个变化 1.3.4 模式帮助我们解决问题 第2章 Delphi的模式编程机制 2.1 对象模型机制 2.1.1 对象模型 2.1.2 对象建模和模式编程 2.1.3 对象关系与复用 2.2 动态绑定机制 2.2.1 方法绑定 2.2.2 方法 2.2.3 多态 2.3 类型转换机制 2.3.1 类型 2.3.2 向上转型 2.3.3 向下转型 2.4 接口抽象机制 2.4.1 接口的概念 2.4.2 抽象类 2.4.3 对象接口 2.4.4 抽象类与对象接口的比较 2.4.5 针对接口而不是针对实现编程 第3章 模式编程法则 3.1 开闭法则(OCP) 3.2 Liskov代换法则(LSP) 3.3 依赖反转法则(DIP) 3.4 接口隔离法则(ISP) 3.5 单一职责法则(SRP) 第二部分 创建型模式编程 第4章 工厂方法模式(Factory Method) 4.1 模式解说 4.2 结构和用法 4.2.1 模式结构 4.2.2 代码模板 4.2.3 问题讨论 4.3 范例与实践 4.3.1 利用工厂方法模式设计可动态切换持久层机制的应用 4.3.2 范例小结 第5章 抽象工厂模式(Abstract Factory) 5.1 模式解说 5.2 结构和用法 5.2.1 模式结构 5.2.2 代码模板 5.3 范例与实践 5.3.1 用抽象工厂模式动态构造界面风格 5.3.2 WebSnap的Web Module架构与抽象工厂模式 5.3.3 范例小结 第6章 建造者模式(Builder) 6.1 模式解说 6.2 结构和用法 6.2.1 模式结构 6.2.2 代码模板 6.3 范例与实践 6.3.1 一个数据集对象产品的建造者模式 6.3.2 范例小结 第7章 单例模式(Singleton) 7.1 模式解说 7.2 结构和用法 7.2.1 模式结构 7.2.2 代码模板 7.2.3 Delphi对象构造机制与单例模式 7.3 范例与实践 7.3.1 一个共享数据库连接的单例模式范例 7.3.2 范例小结 第8章 原型模式(Prototype) 8.1 模式解说 8.2 结构和用法 8.2.1 模式结构 8.2.2 代码模板 8.3 范例与实践 8.3.1 Delphi对象的克隆 8.3.2 用原型模式克隆字体 8.3.3 Delphi对象流化与原型模式 8.3.4 范例小结 第9章 适配器模式(Adapter) 9.1 模式解说 9.2 结构和用法 9.2.1 类的适配器模式 9.2.2 对象的适配器模式 9.2.3 问题讨论 9.3 范例与实践 9.3.1 用适配器模式包装第三方API的范例 9.3.2 范例小结 第10章 桥接模式(Bridge) 10.1 模式解说 10.2 结构和用法 10.2.1 模式结构 10.2.2 代码模板 10.3 范例与实践 10.3.1 使用桥接模式改进数据持久层的健壮性 10.3.2 基于桥接模式的一个数据视图程序 10.3.3 范例小结 第11章 合成模式(Composite) 2 11.1 模式解说 11.2 结构和用法 11.2.1 模式结构 11.2.2 代码模板 11.2.3 问题讨论 11.3 范例与实践 11.3.1 合成模式在组织机构管理系统中的应用 11.3.2 范例小结 第12章 装饰者模式(Decorator) 12.1 模式解说 12.2 结构和用法 12.2.1 模式结构 12.2.2 代码模板 12.2.3 问题讨论 12.3 范例与实践 12.3.1 装饰者模式在图片观赏器中的应用 12.3.2 范例小结 第13章 门面模式(Facade) 13.1 模式解说 13.2 结构和用法 13.2.1 模式结构 13.2.2 代码模板 13.2.3 问题讨论 13.3 范例与实践 13.3.1 门面模式和分布式系统的设计优化 13.3.2 用门面模式设计的COM+银行转账系统 13.3.3 COM+银行转账系统实现代码剖析 13.3.4 范例小结 第14章 享元模式(Flyweight) 14.1 模式解说 14.2 结构和用法 14.2.1 模式结构 14.2.2 代码模板 14.2.3 问题讨论 14.3 范例与实践 14.3.1 对象池技术和享元模式 14.3.2 享元模式在任务调度系统中的应用 14.3.3 范例小结 第15章 代理模式(Proxy) 15.1 模式解说 15.2 结构和用法 15.2.1 模式结构 15.2.2 代码模板 15.3 范例与实践 15.3.1 代理模式在数据库程序中的应用 15.3.2 范例小结 第四部分 行为型模式编程 第16章 责任链模式(Chain of Responsibility) 16.1 模式解说 16.2 结构和用法 16.2.1 模式结构 16.2.2 代码模板 16.2.3 问题讨论 16.3 范例与实践 16.3.1 责任链模式在项目审批系统中的应用 16.3.2 责任链模式对代码的重构 16.3.3 范例小结 第17章 命令模式(Command) 17.1 模式解说 17.2 结构和用法 17.2.1 模式结构 17.2.2 代码模板 17.2.3 问题讨论 17.3 范例与实践 17.3.1 Delphi的Action编程机制与命令模式 17.3.2 一个兼有撤销重做功能的文本编辑器范例 17.3.3 范例小结 第18章 解释器模式(Interpreter) 18.1 模式解说 18.2 结构与用法 18.2.1 模式结构 18.2.2 代码模板 18.3 范例与实践 18.3.1 一个罗马数字到阿拉伯数字的转换器程序 18.3.2 范例小结 第19章 迭代子模式(Iterator) 19.1 模式解说 19.2 结构与用法 19.2.1 模式结构 19.2.2 代码模板 19.2.3 问题讨论 19.3 范例与实践 19.3.1 一个基于迭代子模式的图片播放器 19.3.2 范例小结 第20章 中介者模式(Mediator) 20.1 模式解说 20.2 结构与用法 20.2.1 模式结构 20.2.2 代码模板 20.2.3 问题讨论 20.3 范例与实践 20.3.1 中介者模式在聊天室系统中的应用 20.3.2 范例小结 第21章 备忘录模式(Memento) 21.1 模式解说 21.2 结构与用法 21.2.1 模式结构 21.2.2 代码模板 21.2.3 问题讨论 21.3 范例与实践 21.3.1 备忘录模式在地理信息系统中的应用 21.3.2 范例小结 第22章 观察者模式(Observer) 22.1 模式解说 22.2 结构与用法 22.2.1 模式结构 22.2.2 代码模板 22.2.3 问题讨论 22.3 范例与实践 22.3.1 观察者模式在界面色彩主题中的应用 22.3.2 范例小结 第23章 状态模式(State) 23.1 模式解说 23.2 结构与用法 23.2.1 模式结构 23.2.2 代码模板 23.2.3 问题讨论 23.3 范例与实践 23.3.1 状态模式在信用卡账户管理系统中的应用 23.3.2 范例小结 第24章 策略模式(Strategy) 24.1 模式解说 24.2 结构与用法 24.2.1 模式结构 24.2.2 代码模板 24.2.3 问题讨论 24.3 范例与实践 24.3.1 策略模式在酒店管理系统中的应用 24.3.2 范例小结 第25章 模板方法模式(Template Method) 25.1 模式解说 25.2 结构与用法 25.2.1 模式结构 25.2.2 代码模板 25.2.3 问题讨论 25.3 范例与实践 25.3.1 模板方法在离线数据库系统中的应用 25.3.2 范例小结 第26章 访问者模式(Visitor) 26.1 模式解说 26.2 结构与用法 26.2.1 模式结构 26.2.2 代码模板 26.2.3 问题讨论 26.3 范例与实践 26.3.1 访问者模式在薪酬福利管理中的应用 26.3.2 范例小结 主要参考文献
内联函数(Inlining) D7中的inline关键字作为保留字并不会对编译器产生实际作用,在2009中此关键字起到内嵌到代码中起到实际作用。语法如下: function foo: Integer; inline; 内部函数/过程也可以使用,但在D2009测试版中,类方法的内部函数使用inline后不认Self指针;类的子过程/子函数,也可以使用inline关键字,但没有实际效果,且方法/继承方法(virtual/override)不能使用。 重载运算符(Operator Overloading) 可以重载部分运算符,如+、-、类型转换等,在D2006只支持到record,但从2007开始支持到Class,以下示例修改自官网: TMyClass = class // Addition of two operands of type TMyClass class operator Add(a, b: TMyClass): TMyClass; // Subtraction of type TMyClass class operator Subtract(a, b: TMyClass): TMyclass; // Implicit conversion of an Integer to type TMyClass class operator Implicit(a: Integer): TMyClass; // Implicit conversion of TMyClass to Integer class operator Implicit(a: TMyClass): Integer; // Explicit conversion of a Double to TMyClass class operator Explicit(a: Double): TMyClass; end; class operator TMyClass.Add(a, b: TMyClass): TMyClass; begin //... end; var x, y: TMyClass begin x := 12; // Implicit conversion from an Integer y := x + x; // Calls TMyClass.Add(a, b: TMyClass): TMyClass end; 类助手(Class Helpers) Helper是对原Class的扩展,是我们在不修改原类的基础上增加类方法,并加入原类的空间中。在Delphi中,对对象的调用实际上采用了两个步骤,首先是把对象地址放入eax寄存器中,然后call类方法,所以如果不使用继承类增加数据的话,用父类调用继承类的方法是没问题的,所以其实这样的方法在D7中也可以使用,但却很麻烦。所以Class Helper起到的就是这个作用,在Class Helper中可以增加的就是与实例无关的内容,所以任何需要增加实例Size的活VMT的功能不能声明,例如变量、方法等,但只占用类空间的没关系,如class var。在应用上我们可以通过这种方法方便的给VCL一类控件加上某个属性。 TFoo = class helper for TControl private function GetA: Integer; public class var X: Integer; procedure MSG(var Message: TMessage); message WM_MYMESSAGE; procedure ProcFoo; property A: Integer read GetA; end; // ... procedure TForm1.Foofoo; begin ProcFoo; // TControl -> TWinControl -> TScrollingWinControl-> TCustomForm -> TForm -> TFrom1: Call TFoo.ProcFoo end; strict关键字(Keyword “strict”) 众所周知,在Delphi中,类的private和protected域中的变量可以被同一单元中可以自由的被访问(Delphi的类没有“友元”的概念,但同一个unit中可以说自动友元化了),而并非是真正的私有或只能被继承类访问。而strict关键字的作用就是使该内容变成严格OO意义上的private/protected作用域,这点没有什么多说的。语法: strict private // Blah... strict protected // Blah... 结构方法(Records with Methods) 也没什么特别的,就是和class差不多,就一个不用创建和销毁、不能继承、没有作用域之类的类,很容易掌握,所以这里就不多介绍了。但是很有意思的是带参数的constructor可以通过编译,可能是为了初始化的方便吧。 抽象类和固实类(Abstract and Sealed Classes) 这两个概念在OO中也并不陌生,抽象类是不应该创建实例的(但D2006起的编译器就不给检查,连个Warning都没有,这还有啥用啊 -.- ),而固实类是不能被继承的。语法: TAnAbstractClass = class abstract // or (TParentClass) // Blah... end; TASealedClass = class sealed(TAnAbstractClass) // or empty // Blah... end; 类常量、类变量、类属性与静态类方法(Class const/var/property and Static Class Methods) 老的Delphi中只提供了类方法,而没有提供类变量、类常量和类属性,这真的是很不方便。这里先区分一下我所使用的类(Class)和对象(Object)即类的实例(Instance of Class)。当在Delphi中声明一个类的时候,这个类是有实际地址的,该地址记录了许多类的相关信息,比如实例的Size啊、方法信息啊一堆东西,而创建一个对象的时候则把类实例化,在堆(Heap)中分配一块地址,包括内部数据和VMT之类的东西。在调用实例的时候,首先要知道对象地址,然后才能访问内部变量和调用方法时使用Self指针即实例地址;而在调用类方法的时候,eax中的并不是实例的地址而是类的地址,然后再call方法,这时的Self指针并非实例地址而是类地址。所以对于每一个类和继承类来说,包括它和它的继承类的所有实例,类变量、常量都是同一个,这样就存在了一个唯一的可供使用的变量或常量,方便同步并且不需要使用较多的内存(可以参考C#中的类,不过C#中不允许从实例直接访问类变量、常量、方法)。而静态类方法则是在使用这个类方法的时候不传入class地址,也就是说没有Self指针,这样的类方法的访问开销要小于普通的类方法;这自然也就意味着,该类方法不能被继承(不能virtual/override)。另外,类属性的get/set方法必须使用静态类方法。 TFooClass = class private class procedure SetFoo(const Value: Integer); static; // A Static Class Method protected class var FX : Integer; // class var public const FC: Integer = 10; // class const class procedure VirtualProc; virtual; class property X: Integer read FX write FX; // class property class property Foo: Integer read FC write SetFoo; end; 类内部类型与嵌套类(Class Types and Nested Classes) 可以说现在的Class的域几乎相当于原来的整个unit,以前不能放里面的元素现在都可以放里面了,这个也没什么好多说的,试验一下就很容易明白了。 终方法(Final Methods) 这个也是建立在方法的基础上的,在override后使用final关键字,则表示该方法不能再被子类继承下去了。 TAClass = class public procedure Foo; virtual; end; TFinalMethodClass = class(TAClass) public procedure Test; override; final; // A Final Method end; For-in循环(For-in Loop) 这个应该是受.Net影响吧,支持遍历一个数组或提供了GetEnumerator函数的类。GetEnumerator要求返回一个类的实例,该类包含有Current属性和MoveNext方法。 procedure Foo(List: TStrings); i : Integer; lst : array[0..100]of Integer; s : string; begin for i in lst do ; for s in List do ; // Support of TStrings.GetEnumerator end;

5,392

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧