Delphi 如何覆盖继承的属性?

Delphi 如何覆盖继承的属性?,delphi,inheritance,properties,overriding,Delphi,Inheritance,Properties,Overriding,我有一个类(TMyClass),它有一个属性(Items:TItems) 新的“Items”属性是从TItems继承的,但是当我安装组件时,TExItems的新属性“NewProb”没有出现,看起来“Items”属性仍然是TItems而不是TExItems…如何覆盖它 谢谢 修改: 这是真正的代码 类型 TKHAdvSmoothDock=类 TKHAdvSmoothDockItem = class(TAdvSmoothDockItem) private FImageIndex: TImage

我有一个类(TMyClass),它有一个属性(Items:TItems)

新的“Items”属性是从TItems继承的,但是当我安装组件时,TExItems的新属性“NewProb”没有出现,看起来“Items”属性仍然是TItems而不是TExItems…如何覆盖它

谢谢

修改: 这是真正的代码

类型 TKHAdvSmoothDock=类

TKHAdvSmoothDockItem = class(TAdvSmoothDockItem)
private
  FImageIndex: TImageIndex;
  procedure SetImageIndex(const Value: TImageIndex);
protected

public

published
  property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
end;

TKHAdvSmoothDockItems = class(TAdvSmoothDockItems)
private
  FOwner: TKHAdvSmoothDock;
  FOnChange: TNotifyEvent;
  function GetItem(Index: Integer): TKHAdvSmoothDockItem;
  procedure SetItem(Index: Integer; const Value: TKHAdvSmoothDockItem);
protected
  function GetOwner: TPersistent; override;
public
  constructor Create(AOwner: TKHAdvSmoothDock);
  function Add: TKHAdvSmoothDockItem;
  function Insert(Index: Integer): TKHAdvSmoothDockItem;
  property Items[Index: Integer]: TKHAdvSmoothDockItem read GetItem write SetItem; default;
  procedure Delete(Index: Integer);
published
  property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;

TKHAdvSmoothDock = class(TAdvSmoothDock)
private
  FImageChangeLink: TChangeLink;
  FImages: TCustomImageList;
  FItems: TKHAdvSmoothDockItems;
  procedure ImageListChange(Sender: TObject);
  procedure SetImages(const Value: TCustomImageList);
  procedure SetItems(const Value: TKHAdvSmoothDockItems);
  function GetItems: TKHAdvSmoothDockItems;
  { Private declarations }
protected
  procedure UpdateImagesFromImageList;
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
published
  property Images: TCustomImageList read FImages write SetImages;
  property Items: TKHAdvSmoothDockItems read GetItems write SetItems;
end;

注意。

属性不能是虚拟的,因此不能重写它们。它们可以隐藏,因为在
TExMyClass
的上下文中,对
项的引用将解析为在该类中声明的属性,而不是在祖先中声明的属性

如果某个对象的静态(声明的,编译时)类型为
TMyClass
Items
将始终引用该类中的对象,即使其运行时类型为
TExMyClass


您可以在基类中将
SetItems
声明为受保护和虚拟,然后在子体中重写它,而不是声明一个恰好具有相同名称的全新属性。

属性getter和setter可以是虚拟的,然后通过继承类重写,请参见下面更新的示例。您的示例代码有一个警告,那就是您试图更改属性的类型,这是不允许的。我建议您在
TExMyClass.SetItems
中检查
值是否为TExItems
,但在
TExMyClass
的所有方法中使用继承的Items属性并强制转换为TExItems,以及进一步的继承者

TItems = class;

TMyClass = class(TComponent)
private
   FItems: TItems;
   procedure SetItems(const Value: TItems); virtual;
protected
  property Items: TItems read FItems write SetItems;
end;

TExItems = class(TItems)
private
  FNewProb: Integer;
protected

public

published
  property NewProp: Integer read FNewProb write FNewProb;
end;

TExMyClass = class(TMyClass)
private
   procedure SetItems(const Value: TItems); override;
end;

您可以实现和覆盖getItem和setItem方法

仅为TMyClass实现属性项

property Items: TItems read getItems write setItemps;
对于TMyClass:

public:  
function getItems : TItems; virtual;
procedure setItems(items: TItems); virtual;
对于TExMyClass:

public:
function getItems : TItems; override;
procedure setItems(items: TItems); override;

function TExMyClass.getItems : TItems;
begin
  result := fItems;
end;

procedure TExMyClass.setItems(items : TItems);
begin
  self.itmes := items;
end;

所以,TExMyClass.items.className=TExItems

从技术上讲,您不能重写属性,但可以通过几种方式模拟重写。有关最基本的礼仪,请参见示例

现在我没有
TAdvSmoothDock
的代码,所以剩下的只是猜测。当
TAdvSmoothDock.Items
的属性getter和setter是虚拟的时,您可以重写它们。但是在更高级的组件中,我认为TMS中的那些是,那么就有很大的机会
TAdvSmoothDock
拥有一个受保护的
CreateItem
方法,每当需要一个可以被覆盖的新项时就会调用该方法。如果是这种情况,那么您应该像这样实施它:

function TKHAdvSmoothDock.CreateItem: TAdvSmoothDockItem;
begin
  Result := TKHAdvSmoothDockItem.Create;
end;
然后像这样使用它:

TKHAdvSmoothDockItem(AKHAdvSmoothDock.Items[I]).ImageIndex := ...

这与尝试使用同一Lines对象的多个TMemo的问题相同

由于
TCustomMemo
delcares在其
private
部分
FLines:TStrings不可能有多个TMemo使用相同的
FLines

工作的唯一方法(我仍然知道)是将整个
TCustomMemo
类完全复制为
TLinkedCustomMemo
,但定义
FLines:TStrings在公共部分;还需要克隆“TMemo”,但引用的是
TLinkedCustomMemo
,而不是
TCustomMemo

然后使用delcarcing
TMemo=class(TLinkedMemo)
的破解,您将拥有对
FLines
的公共访问权限,因此您可以在所有其余链接的备忘录上用主TMemo的对象替换该对象

为什么在TMemos的内容上会有这样的链接? 简单的答案可能是:有多个TMemo显示相同的文本,这样用户可以一次看到(和编辑)两个(或更多)不同的部分,就像一些电子表格一样。。。它通常还包括它们之间的水平拆分器、同步水平滚动条等

有时候做一些看起来很简单的事情,其实很复杂! 只是因为VCL设计有问题

对于TMemos的示例。。。为什么它们没有被定义为基于TStringList插入TStrings的Lines属性?这样,我们可以同时对多个TMemo使用相同的字符串列表

如果要看,内部是如何依赖于这样的。。。搜索类
TMemoStrings
(它出现在StdCtrls的实现部分)。为什么它必须只有一个TMemo?,为什么它必须有?为什么不用TStringList来代替那些该死的东西呢

当某些课程关闭时。。。它来自于声明类的黑客方式。。。但是,如何只更改控件的一个属性而不需要完全复制某些类(只是为了更改这么小的内容)

哦,是的,内容链接备忘录的实际示例可能是:

  • 让用户(同时)看到文本文件的两个不同部分,而无需双倍的内存存储
  • 或者更好的示例:用户希望在第3行编辑一个单词,在第1000万行编辑另一个单词,而无需滚动
因此,您可以放置两个TMemo并链接Lines属性,这样用户就可以从两个备忘录中编辑这样的Lines属性(在不同的点上),而无需一直上下滚动

另一个样本:

  • 用户想要编辑一百万到一百万行加上二十行,但需要同时看到十到二十行
  • 必须使用
    复制
    的备忘录是不可能的,32位窗口上的内存超过3GiB(不允许),每个备忘录需要>1.6GiB的RAM。。。等等
  • 复制这样的数据既不是一个选项,用户编辑第二个备忘录,但第一个必须同步。。。所以在散焦之后(或者编辑之后,如果你想好看的话),你必须把一张备忘录中的所有数据复制到另一张备忘录中。。。计算时间? -等
有这么多的样品。。。最重要的是我想不出来的

因此,以一般形式回答您的问题,“如何对类进行黑客攻击以稍微修改它”:

  • 克隆在一个新单元中定义类的代码,将该单元称为某种东西,以明确它是为了在经过一些修改后克隆该类
  • TKHAdvSmoothDockItem(AKHAdvSmoothDock.Items[I]).ImageIndex := ...