1、overload

在Pascal语法规则中,同一个UNIT里是不能存在两个同名的函数的,例如:

function func(): Boolean;
function func(const x: Char): Boolean;

这样是会出语法错误的,原因是因为标识符规则限制。但是问题出来了,如果我们需要几个功能相似但是参数不同的函数,那么根据标识符规则,我们就必须定义几个不同名,但是功能相同或相似的函数。
    如,假设我需要一个函数,要实现返回参数一减去参数二后的值,那么我们就将这样定义函数:

function SubInt(const Value1, Value2: Integer): Integer;
functino SubReal(const Value1, Value2: Real): Real;
function SubDouble(const Value1, Value2: Double): Double; implementation function SubInt(const Value1, Value2: Integer): Integer;
begin
Result:= Value1 - Value2;
end; functino SubReal(const Value1, Value2: Real): Real;
begin
Result:= Value1 - Value2;
end; function SubDouble(const Value1, Value2: Double): Double;
begin
Result:= Value1 - Value2;
end;

我们可以看到,这三个函数除了参数名不同外,实现部分是一样的,这为程序的一致性带来了一定的麻烦。如果能定义一个同名函数来处理这几种不同情况的话,便有利于代码的重用,也有利于我们的记忆。这时我们就可以用overload来完成我们的需求了。

function Sub(const Value1, Value2: Integer): Integer; overload;
function Sub(const Value1, Value2: Real): Real; overload;
function Sub(const Value1, Value2: Double): Double; overload; implementation function Sub(const Value1, Value2: Integer): Integer;
begin
Result:= Value1 - Value2;
end; function Sub(const Value1, Value2: Real): Real;
begin
Result:= Value1 - Value2;
end; function Sub(const Value1, Value2: Double): Double;
begin
Result:= Value1 - Value2;
end;

由此可见,名字相同而参数的数据类型或数量不同的函数,称之为overload函数。这是因为编译器在编译时不仅使用了函数名的信息,还使用了参数类型和数量的信息,通过组合这些信息可以确定分配地址时需要的唯一标识,通常我们叫他signature。例如:

Sub(1, 2);     // 调用的是 function Sub(const Value1, Value2: Integer): Integer;
Sub(1.0, 2.0); // 调用的是 function Sub(const Value1, Value2: Real): Real;

这里要说明一下,如果是同名函数,并且参数也相同,只是返回值不同的话,是不能实现overload的。

2、override:
    前面我说过,在派生一个新类的时候,首先会继承父类中的所有可继承部分,那么就意味着,默认情况下,父类所有的非私有

部分的类成员或方法都已经包含在新类中。
    但是,如果我们要为类的一个方法添加新的代码而又不希望重写父类方法中原有功能的话,我们可以用override来实现方法的覆盖,并用inherited来继承(或者可以说调用)父类方法中的方法功能

type
TBaseClass = class(TObject)
// 定义一个新的父类
protected
FMessage: string;
public
constructor Create(); // 构造方法
procedure MessageBox(); virtual; // 显示字符串
end; TChildClass = class(TBaseClass)
// 定义一个TBaseClass的派生类
public
procedure MessageBox(); override; // 重载父类中的方法
end; implementation constructor TBaseClass.Create;
begin
inherited Create(); // 继承父类中的构造方法Create
FMessage:= ClassName; // 初始化信息字符串为类名
end; procedure TBaseClass.MessageBox;
begin
ShowMessage(FMessage); // 显示字符串
end; procedure TChildClass.MessageBox;
begin
FMessage:= FMessage + FMessage;
inherited MessageBox(); // 继承父类中原有MessageBox方法的原有功能
end;

好,我们可以编写一个简单的例子来调用一下:

var
Child: TChildClass;
begin
Child:= TChildClass.Create;
Child.MessageBox();
Child.Free;
end;

代码执行后,应该可以看到一个弹出“TChildClassTChildClass”字符串的对话框。
    以上代码只是简单的演示了类方法的继承,也许你会奇怪,为什么TBaseClass的构造方法Create没有用override关键字指定,却同样可以inherited来继承父类的该方法,其实不用override也是可以实现继承的(在这里如果你加上override反而会出语法错误,因为TObject类的Create是一个静态方法,而静态方法是不允许被override的),那么他们有什么不一样的呢?我们来看下面的例子:

var
Child: TBaseClass;
begin
Child:= TChildClass.Create;
Child.MessageBox();
Child.Free;
end;

执行这段测试代码和我们上面的代码是一样的效果的。然后我们再把TBaseClass类的方法MessageBox后的virtual关键字和子类中的override关键字去掉,再执行一次看看,应该是看到一个弹出“TChildClass”字符串的对话框。
    这是为什么呢?原因是因为virtual关键字,下面简单的说明一下virtual关键字:

3、virtual和dynamic方法
    virtual关键字是指定方法为虚方法,Object Pascal中,默认情况下,所有方法都是静态的(当然和类方法不同),静态方法的特点是,在对象被创建的时候,编译器会分配所有调用静态方法时所指定的内存地址,也就是说,编译期即指定了调用的具体方法。
    而virtual和dynamic方法(虚方法和动态方法)则是在调用时动态分配的。他们的语义是相同的,唯一不同的是,他们的实现方法和调用方法,这涉及到DELPHI的编译机制。

Delphi的编译器会自动维护用于添加虚方法的虚方法表(VMT)和用于添加动态方法的动态方法表(DMT)。
    虚方法表存放的是类及其基类声明的所有虚方法指针。每一个类都有并且只有一个虚方法表,当然每一个虚方法表都有一个入口。无论一个类是否有他自己定义的虚方法,只要他继承了祖先类的虚方法,他也就会有自己的虚方法表,并列举出他继承的所有虚方法。因为每一个类都有一个自己的虚方法表,Delphi就可以使用虚方法表来识别一个类,实际上,一个类引用就是指向类的虚方法表的指针。
    由于基类和派生类的虚方法表之间有过强的关联性,因此派生类继承了祖先类的虚方法,也就是说派生类的虚方法表的前面一部分必须与基类相同。而当基类和派生类不在同一个DLL或EXE中的时候,这个要求是很难满足的。基类一旦改变,派生类如果不重新编译,将导致错误。另外,如果类的继承很深,那么虚方法表将会因不断继承的虚方法而膨胀,导致效率低下。
    而动态方法则可以解决这个问题,每一个类的动态方法表中只维护部分的动态方法,也就是说动态方法表只列出了该类所声明的动态方法,他并不包括从祖先类那里继承来的动态方法。动态方法表使用了一种独特的编号和检索系统,当调用动态方法时,会在动态方法表中的Indexes数组中查找该方法的代号,一旦找到匹配该方法的代号,则方法指针会到相应的地址中调用方法。如果没有找到,则会搜索祖先类中的动态方法表。这样虽然解决了虚方法表膨胀的问题,但是产生了执行效率的问题。

总的来说,虚方法侧重于提高速度,动态方法侧重于节省内存,如果某方法其后代类基本都需要override的,那么推荐使用virtual,如果某方法不经常或者几乎不在后代类中被override的,则推荐使用dynamic。

4、abstract方法
    abstract方法就是我们常说的抽象方法,该方法只能有声明而不能有实现部分,一般只是提供给派生类override使用的,所以一般abstract关键字和virtual是一起出现的。而一般含有抽象方法的类一般我们叫他虚类。

类方法
    类方法和C中的static方法有点相似,Object Pascal中的类方法是不需要实例化对象就可以调用的方法。由于他不需要为对象分配内存空间就可以调用他,那么也就意味着在类方法中不能引用类中的其他数据成员。
    类方法的声名如下:

type
TNewClass = class(TObject)
public
class procedure AClassFunciton(...): ...;
end;

  

Delphi 方法:overload、override、virtual、dynamic、abstract的更多相关文章

  1. 转: Delphi的OverRide、OverLoad和Virtual方法

    http://blog.csdn.net/ckli/article/details/2201418 override 重写 也叫覆盖 .方法的重写Overriding和重载Overloading是Ja ...

  2. sealed、new、virtual、abstract与override 趣解

    1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于 方法或属性时,sealed修饰符必须始终与override一起使用. ...

  3. C#中隐藏(new)、方法重写(override)、重载(overload)的区别

    转自:http://www.cnblogs.com/glife/archive/2009/12/28/1633947.html 重载.重写和隐藏的定义: 重载:public string ToStri ...

  4. sealed、new、virtual、abstract与override 总结

    1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于方法或属性时,sealed修饰符必须始终与override一起使用. ...

  5. C# 方法重载 overload、方法重写 override、隐藏 new

    一.重载:同一个作用域内发生(比如一个类里面),定义一系列同名方法,但是方法的参数列表不同.这样才能通过传递不同的参数来决定到底调用哪一个. 值得注意的是,方法重载只有通过参数不同来判断调用哪个方法, ...

  6. 1.隐藏继承的成员new / 虚方法(override)/ abstract / 多态 ----- 重写

    总结: 1. 在继承上, new/override没区别 2. 在多态上,new不支持多态,override支持 在C#中改变类中相同名称的方法的实现过程中有三种方式:重载.重写和覆盖. 重载:指具有 ...

  7. virtual和abstract

    virtual和abstract都是用来修饰父类的,通过覆盖父类的定义,让子类重新定义. 共同点:如果用来修饰方法,前面必须添加public,要不然就会出现编译错误:虚拟方法或抽象方法是不能私有的. ...

  8. C# virtual和abstract的

    virtual和abstract都是用来修饰父类的,通过覆盖父类的定义,让子类重新定义. 它们有一个共同点:如果用来修饰方法,前面必须添加public,要不然就会出现编译错误:虚拟方法或抽象方法是不能 ...

  9. asp.net中virtual和abstract的区别

    这篇文章主要介绍了asp.net中virtual和abstract的区别,较为详细的分析了virtual与abstract的概念与具体用法,并以实例的形式予以总结归纳,需要的朋友可以参考下 本文实例分 ...

随机推荐

  1. hadoop HA集群的安装

    1.hadoop集群规化 ip 主机名 安装软件 角色 运行进程 10.124.147.22 hadoop1 jdk.zookeeper.hadoop namenode/zookeeper/jobhi ...

  2. 1.MVC的初步了解

    1.MVC简单介绍 1)原理(如图)如果想更加深入了解原理,可以访问此地址(https://www.cnblogs.com/uicodeintoworld/p/8950877.html) 理解:客户端 ...

  3. 【leetcode】991. Broken Calculator

    题目如下: On a broken calculator that has a number showing on its display, we can perform two operations ...

  4. QT blockingmaster例子学习

    dialog.h: #ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include "masterthread.h&q ...

  5. 木棍加工(dp,两个参数的导弹拦截问题)

    题目描述 一堆木头棍子共有n根,每根棍子的长度和宽度都是已知的.棍子可以被一台机器一个接一个地加工.机器处理一根棍子之前需要准备时间.准备时间是这样定义的:     第一根棍子的准备时间为1分钟:   ...

  6. Network基础(一):配置计算机名及工作组、TCP/IP地址配置、网络连通性测试

    一.配置计算机名及工作组 目标: 本例要求为修改计算机名并加入工作组: 设置计算机名:姓名拼音 设置工作组名:TARENA-NETWORK 方案: 修改Windows 2008服务器的计算机名(可设为 ...

  7. 微信小程序学习笔记(四)--框架-视图层

    WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合基础组件.事件系统,可以构建出页面的结构. 数据绑定 使用{{}}绑定数据. 简单绑定 <view clas ...

  8. Vuetify按需加载配置

    自己配置vuetify按需加载的步骤,在此记录: 执行npm install vuetify –save 或 yarn add vuetify添加vuetify添加依赖执行npm install -- ...

  9. 慎用margin系列2---ie6双倍边距问题

    IE6下有一个著名的margin双倍bug 一.什么是双边距Bug? 先来看图: 我们要让绿色盒模型在蓝色盒模型之内向左浮动,并且距蓝色盒模型左侧100像素.这个例子很常见,比如在网页布局中,侧边栏靠 ...

  10. CF1216X

    由于rating限制,和慎老师用小号打了一场div 3 从A到F都没啥思维含量..感觉最难想的就是C了?? CF1216C 考完以后想hack一下这道题,然后发现满屏都是分类讨论 我大概是写不动 or ...