首页 / 知识
关于oop:在Delphi中重新引入功能
2023-04-14 19:30:00

Reintroducing functions in Delphi
在Delphi中使用 如果您的子类包含与父类中的虚拟函数同名的函数,并且未使用override修饰符声明该子函数,则这是编译错误。 在这种情况下添加reintroduce修饰符可以修复该错误,但是我从未掌握过编译错误的原因。 如果您在后代类中声明的方法与祖先类中的方法具有相同的名称,那么您将隐藏该祖先方法-这意味着,如果您具有该后代类的实例(被称为该类),则您将不了解祖先的行为。当祖先的方法是虚拟的或动态的时,编译器将向您发出警告。 现在,您有两种选择可禁止显示该警告消息: 因此,覆盖和重新引入之间的差异在于多态性。使用reintroduce,如果将后代对象强制转换为父类型,则调用该方法将获得祖先方法,但是如果访问它的后代类型,则将获得后代的行为。使用override,您总是可以得到后代。如果祖先方法既不是虚拟方法也不是动态方法,则重新引入将不适用,因为该行为是隐式的。 (实际上,您可以使用课程帮手,但我们现在不会去那里。) 尽管Malach说了什么,您仍然可以在重新引入的方法中调用继承,即使父代既不是虚拟的也不是动态的。 本质上,重新引入就像重写一样,但是它与非动态和非虚拟方法一起使用,并且如果通过祖先类型的表达式访问对象实例,则它不会替代行为。 进一步说明: 重新引入是一种向编译器传达您没有犯错误的意图的方法。我们使用override关键字覆盖了祖先中的方法,但是它要求祖先方法是虚拟的或动态的,并且您希望在访问对象作为祖先类时更改行为。现在输入重新介绍。它可以让您告诉编译器您并非偶然创建了一个与虚拟或动态祖先方法同名的方法(如果编译器没有警告您,这将很烦人)。 这里有很多答案,说明为什么让您静默隐藏成员函数的编译器是个坏主意。但是,没有现代编译器会默默地隐藏成员函数。即使在允许这样做的C ++中,也总是会有关于它的警告,这应该足够了。 那么为什么要"重新引入"呢?主要原因是当您不再查看编译器警告时,这种错误实际上可能偶然出现。例如,假设您从TComponent继承,而Delphi设计人员向TComponent添加了新的虚函数。坏消息是您的派生组件,该组件是您五年前编写并分发给他人的,已经具有该名称的功能。 如果编译器刚刚接受这种情况,则某些最终用户可能会重新编译您的组件,请忽略该警告。奇怪的事情会发生,而你会受到责备。这要求他们明确接受该功能不是同一功能。 RTL使用重新引入来隐藏继承的构造函数。例如,TComponent有一个带有一个参数的构造函数。但是,TObject具有无参数的构造函数。 RTL希望您在实例化新的TComponent时仅使用TComponent的单参数构造函数,而不使用从TObject继承的无参数构造函数。因此,它使用重新引入来隐藏继承的构造函数。这样,重新引入有点像在C#中将无参数构造函数声明为私有。
tl; dr:尝试覆盖非虚拟方法没有任何意义。添加关键字 首先,"重新引入"打破了继承链,不应使用,我的意思是永远不会。在与Delphi合作的整个过程中(大约10年),我偶然发现了许多使用此关键字的地方,这在设计中一直是错误的。 考虑到这一点,这是最简单的工作方式: 就像我说的那样,这是纯粹的邪恶,必须不惜一切代价避免(好吧,至少我是这样认为的)。就像使用goto-只是一种糟糕的风格:D 重新引入修饰符的目的是防止出现常见的逻辑错误。 我将假定重新引入关键字如何解决警告是众所周知的知识,并解释为什么会生成警告以及为什么将关键字包含在语言中。考虑下面的delphi代码;
给定上面的代码,TParent中的两个过程都被隐藏了。要说它们是隐藏的,则意味着无法通过TChild指针调用该过程。编译代码示例会产生一个警告。 [DCC警告] Project9.dpr(19):W1010方法"过程1"隐藏基本类型" TParent"的虚拟方法 为什么只对虚拟功能发出警告,而不对其他发出警告?两者都是隐藏的。 Delphi的一个优点是库设计人员可以发布新版本,而不必担心破坏现有客户端代码的逻辑。这与Java相反,在Java中,向类的父类添加新功能充满了危险,因为类是隐式虚拟的。可以说,上面的TParent位于第3方库中,并且库制造商在下面发布了新版本。
假设我们的客户代码中包含以下代码
对于客户端而言,代码是针对库的版本2还是版本1编译都没有关系,在两种情况下,都按照用户的意图调用TChild.Setup。在图书馆里
如果使用TChild参数调用TestLibrary,则一切都会按预期进行。库设计者不了解TChild.Setup,并且在Delphi中不会造成任何危害。上面的调用正确解析为TParent.Setup。 在Java的等效情况下会发生什么? TestClient将按预期正常工作。 TestLibrary不会。在Java中,所有功能均假定为虚拟的。 Parent.Setup将解析为TChild.Setup,但请记住,编写TChild.Setup时他们不知道将来的TParent.Setup,因此,它们肯定不会调用继承的。因此,如果库设计人员希望调用TParent.Setup,则无论如何都不会调用TParent.Setup。当然这可能是灾难性的。 因此,Delphi中的对象模型需要在子类链的下游显式声明虚拟函数。这样做的副作用是很容易忘记在子方法上添加override修饰符。 Reintroduce关键字的存在为程序员提供了便利。 Delphi的设计旨在通过发出警告来温和地劝说程序员在这种情况下明确说明其意图。 重新引入告诉编译器您要调用此方法中定义的代码作为该类及其后代的入口点,而与祖先链中具有相同名称的其他方法无关。
创建
无论您希望后代方法是否为虚拟方法都是如此:在两种情况下,您都希望打破虚拟链的自然联系。
当祖先类也有一个同名的方法,并且不一定要声明为virtual时,您将看到编译器警告(因为您将隐藏此方法)。 换句话说:您告诉编译器您知道自己隐藏了祖先函数,并用此新函数替换了它,并有意这么做。 为什么要这么做?如果该方法在父类中是虚拟的,则唯一的原因就是要防止多态。否则,仅重写而不调用继承。但是,如果未将父方法声明为虚拟方法(并且您无法更改它,因为例如您不拥有代码),则可以从该类继承并让人们从您的类继承而不会看到编译器警告。 首先,如上所述,您永远不要故意重新引入虚拟方法。重新引入的唯一明智的用法是,祖先(不是您)的作者添加了与后代发生冲突的方法,并且重命名后代方法不是一种选择。其次,您甚至可以在使用不同参数重新引入虚拟类的类中轻松调用虚拟方法的原始版本:
那么重新引入虚拟方法的目的是什么,而不是使事情难以阅读? 由于Framework版本(包括VCL),该语言已被引入。
如果您已有代码库,并且对Framework进行了更新(例如,因为购买了Delphi的较新版本),则引入了一个虚拟方法,其名称与代码库中祖先的方法相同,则
这是您应该使用 reintroduce允许您声明与祖先名称相同但参数不同的方法。它与错误或错误无关!!! 例如,我经常将其用于构造函数...
这使我能够以更简洁的方式为复杂的控件(例如工具栏或日历)创建内部类。我通常有更多的参数。有时,在不传递某些参数的情况下创建类几乎是不可能的,也可能会很混乱。 对于可视控件,可以在Create之后调用Application.Processmessages,这对于使用这些参数可能为时已晚。
|
最新内容
相关内容
调用函数命令linux?
调用函数命令linux?,系统,管理,网络,通用,统一,观察,地址,代码,设备,地方,怎么调用system函数,使用Android的linux命令1、int system(const chlinux虚拟机ls命令?
linux虚拟机ls命令?,系统,信息,时间,命令,最新,标准,工作,名称,文件,目录,linux写脚本,需要ls只显示前10个文件,怎么实现?在linux中如果用ls查linux虚拟机扩容命令?
linux虚拟机扩容命令?,扩大,系统,在线,虚拟机,盘后,工具,硬盘,磁盘,单击,下一步,Linux虚拟机添加新硬盘的全程图解1、先关闭LINUX系统,在vmwarelinux虚拟机系统命令?
linux虚拟机系统命令?,系统,环境,密码,电脑,软件,工具,信息,位置,设备,虚拟机,在虚拟机中启动LINUX系统后,进入图形化界面的命令是什么?创建新linux命令大全虚拟机?
linux命令大全虚拟机?,地址,网络,名字,系统,信息,密码,电脑,状态,首次,名称,在linux中查看虚拟机的IP地址,使用ifconfig命令出来这么多信息,不虚拟机linux拷贝命令?
虚拟机linux拷贝命令?,系统,工具,服务,电脑,软件,项目,虚拟机,异常,命令,文件,如何实现虚拟机linux和主机之间文本的复制和粘贴1、使用 vSpherlinux虚拟机压缩命令?
linux虚拟机压缩命令?,系统,命令,文件,管理,时间,标准,工具,数字,目录,格式,Linux中常用的压缩和解压缩命令汇总1、常用就是tar命令了。参数为linux虚拟机重置命令?
linux虚拟机重置命令?,系统,网络,软件,时间,地址,服务,状态,虚拟机,位置,代理,Windows内置的Linux虚拟机安装之后怎么恢复成安装之前的样子?_linux查询函数命令?
linux查询函数命令?,系统,信息,名称,标准,函数,百度,代码,名字,最新,实时,Linux下查找一个函数在哪个库文件中1、默认状态下,gcc并不搜索数学库linux虚拟机cd命令?
linux虚拟机cd命令?,系统,网络,地址,电脑,状态,密码,软件,虚拟机,命令,控制台,虚拟机中linux9.0装tools调整分辨率时从cdroom下复制压缩安装包linux还原虚拟命令?
linux还原虚拟命令?,系统,工作,地址,命令,位置,百度,基础,信息,管理,目录,Windows内置的Linux虚拟机安装之后怎么恢复成安装之前的样子?_百度.linux虚拟机基本命令?
linux虚拟机基本命令?,系统,名字,密码,环境,电脑,软件,名称,首次,位置,命令,在虚拟机中启动LINUX系统后,进入图形化界面的命令是什么?创建新用