如何覆盖继承的属性?

时间:2012-07-11 12:43:50

标签: delphi inheritance properties override

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

TItems = class;    

TMyClass = class(TComponent)
private
   FItems: TItems;
   procedure SetItems(const Value: TItems);
protected

public

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
   FItems: TExItems;
   procedure SetItems(const Value: TItems);
protected

public

published
  property Items: TExItems read FItems write SetItems;
end.

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

由于

修改: 这是真实代码

型     TKHAdvSmoothDock = class;

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;

问候。

5 个答案:

答案 0 :(得分:1)

属性不能是虚拟的,因此无法覆盖它们。它们可以隐藏,因为在TExMyClass的上下文中,对Items的引用将解析为在该类中声明的属性,而不是在祖先中声明的属性。 / p>

如果您的静态(声明的,编译时)类型为TMyClassItems将始终引用该类中的那个,即使其运行时类型为{{1 }}

您可以在基类中将TExMyClass声明为protected和virtual,然后在后代中覆盖它,而不是声明一个恰好具有相同名称的全新属性。

答案 1 :(得分:1)

属性getter和setter可以是虚拟的,然后通过继承类来覆盖,请参阅下面的示例更新。有一个警告,你是示例代码,那是你试图改变属性的类型,这是不允许的。我建议您检查Value is TExItems中的TExMyClass.SetItems,但使用继承的Items属性并在TExMyClass的所有方法和其他继承者中强制转换为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;

答案 2 :(得分:1)

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

仅为TMyClass

实现属性Item
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!

答案 3 :(得分:1)

从技术上讲,您无法覆盖属性,但可以通过多种方式模仿覆盖。例如,请参阅this answer以获取最基本的方式。

现在我没有TAdvSmoothDock的代码,所以剩下的只是猜测。如果TAdvSmoothDock.Items的属性获取器和设置器是虚拟的,则可以覆盖它们。但是在更高级的组件中,我认为来自TMS的组件是,那么TAdvSmoothDock很可能有一个受保护的CreateItem方法,只要需要一个新的项目就可以调用它。覆盖。如果是这种情况,那么你应该像:

那样实现它
function TKHAdvSmoothDock.CreateItem: TAdvSmoothDockItem;
begin
  Result := TKHAdvSmoothDockItem.Create;
end;

并使用它:

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

答案 4 :(得分:0)

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

TCustomMemo private部分FLines: TStrings; FLines以来,不可能有多个使用相同TCustomMemo的TMemo。

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

然后使用delcaring FLines的hack,您将可以公开访问TMemoStrings,因此您可以在所有其他链接的备忘录上用主TMemo的对象替换该对象。

为什么关于TMemos内容的链接? 简单的答案可能是:有多个TMemo显示相同的文本,因此用户可以一次看到(和编辑)两个(或更多)不同的部分,就像一些SpreadSheets那样...它通常还涉及一个水平分割器之间它们,同步水平滚动条等。

有时做一些看起来很容易的事情,实在太复杂了! 只是由VCL设计错误引起的。

对于TMemos的样本......为什么他们还没有根据TStrings的TStringList insead定义它的Lines属性?这样我们就可以同时为多个TMemo使用相同的字符串列表。

如果想看,内部如何依赖于这样......搜索类copy(它出现在StdCtrls的实现部分)。为什么它必须只有一个TMemo?为什么它必须有?为什么不使用TStringList而不是所有地狱呢?

当某些类如此封闭时...它是以声明类的黑客方式...但是如何只更改控件的属性而不需要完全复制某些类(只是为了改变这么少的东西)? / p>

哦,是的,内容链接备忘录的真实样本可能是:

  • 让用户看到(同时)文本文件的两个不同部分,而不是双倍的内存存储
  • 或者更好的示例:用户想要在第3行编辑一个单词而在另一行上编辑另一个单词而不需要滚动

因此,您放置两个TMemo并链接Lines属性,因此用户可以使用控件在两个备忘录中编辑此类Lines属性(在不同点上),而无需一直向下滚动。

另一个样本:

  • 用户想要编辑一百万到一百万加二十行,但需要同时看到十到二十行。
  • 不能使用TTheClass=class(TheUnit.TTheClass)的备忘录,超过32位Windows上的3GiB RAM(不允许),每个备忘录需要> 1.6GiB的内存......等等。
  • 复制这样的数据既不是选项,也不是用户在第二个备忘录上编辑,但首先必须同步...所以在松散焦点之后(或者只是在编辑之后如果要好看)你必须将所有数据从一个复制到别人的备忘录......计算时间? -etc

有很多样本......最重要的是我无法想象的样本。

以一般形式回答你的问题,“如何破解课程来修改它”:

  1. 克隆在新单元中定义类的代码,调用该单元以清除它是用于克隆该类的一些修改
  2. 仅当您的修改是向后兼容时才使用相同的类名(例如,当添加到TEdid的Align属性时,使用声明为uses的hack),否则使用不同的名称
  3. interface部分Alignment
  4. 的末尾添加此新单元

    就是这样......简单地说,在某些情况下要努力工作。

    我总是建议使用nes类名称,除了将TEdit属性添加到TEdit的示例之外。

    什么时候使用声明的黑客?如果您已经编码了一个完整的应用程序,并想要添加到其上的所有:TEdit;,那么对齐...不是创建新组件,而是将其添加到组件工具,重新定义所有表单以不使用:TMyAlignedEdit并使用TEdit ...您可以简单地添加以使用您的单位和瞧...所有{{1}}现在都有这样的属性,IDE inspertor也会看到它等等。