2

我有一个类(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 = 类;

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;

问候。

4

5 回答 5

3

属性 getter 和 setter 可以是虚拟的,然后被继承类覆盖,请参阅下面的更新示例。对于示例代码有一个警告,那就是您正在尝试更改属性的类型,这是不允许的。我建议您签Value is TExItems入,但使用继承的 Items 属性并在所有方法和进一步继承TExMyClass.SetItems者中转换为 TExItems 。TExMyClass

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;
于 2012-07-11T13:34:14.467 回答
2

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

如果您有静态(声明的,编译时)类型为 的东西TMyClassItems将始终引用该类中的那个,即使它的运行时类型是TExMyClass

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

于 2012-07-11T13:29:04.967 回答
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 !

于 2012-07-11T14:00:22.213 回答
1

从技术上讲,您不能覆盖属性,但可以通过多种方式模拟覆盖。例如,请参阅此答案以了解最基本的方式。

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

function TKHAdvSmoothDock.CreateItem: TAdvSmoothDockItem;
begin
  Result := TKHAdvSmoothDockItem.Create;
end;

并像这样使用它:

TKHAdvSmoothDockItem(AKHAdvSmoothDock.Items[I]).ImageIndex := ...
于 2012-07-11T15:44:22.023 回答
0

It is the same problem as trying to have more than one TMemo that uses the same Lines object.

Since TCustomMemo delcares on its private section FLines: TStrings; it is not possible to have more than one TMemo that uses the same FLines.

The only way (i still know) of working is to fully duplicate the whole TCustomMemo class as TLinkedCustomMemo, but defining FLines: TStrings; on the public section; also need cloning the 'TMemo' but referencing TLinkedCustomMemo, not TCustomMemo

Then using the hack of delcaring TMemo=class(TLinkedMemo) you will have public access to FLines, so you can replace that object, with the object of the main TMemo, on all the rest linked memos.

Why do such Link on the content of the TMemos? Easy answer could be: Have more than one TMemo that shows the same text, so user can see (and edit) two (or more) different parts at a time, like some SpreadSheets do... it normally also involve an horizontal splitter between them, syncing horizontal scrollbars, etc.

Sometimes doing something that seems so easy, it is really so complicated! Just caused by faulty on VCL design.

For the sample of the TMemos... why on the hell they have not been defined its Lines property based on TStringList insead of TStrings? That way we could use the same String List for more than one TMemo at the same time.

If want to see, how internally is dependant on such... search for class TMemoStrings (it appears on implementation section of StdCtrls). Why it must have only one TMemo?, and why it must have at all? why not had used TStringList instead of all that hell?

When some classes are so closed... it comes the hacking way of declaring classes... but how to change only a property of a control without needing to whole duplicate some classes (just to change so little things)?

Oh, yes, a real life sample for a content linked memo could be:

  • Let the user see (at the same time) two different parts of a text file, without double the memory storage
  • Or better sample: the user wants to edit a word on line 3 and another on line ten million without the need to scroll

So you put two TMemo and link the Lines property, so user has the controls to edit such Lines property (on different points) from both memo without need to scroll down and up all the times.

Another sample:

  • User wants to edit lines one million to one million plus twenty but needs to see lines ten to twenty at the same time.
  • Having to memos with a copy is not possible, more than 3GiB of RAM on a 32Bits Windows (not allowed), each Memo would need >1.6GiB of ram each... etc.
  • Duplicating such data is neither an option, user edit on second memo, but first must be on sync... so after loose focus (or just after edit if want good looking) you would must copy all data form one to the others memos... computing time? -etc

There are so much samples... and most important ones are the ones i can not figure.

So answering your question in a general form, "how to hack a class to modify it a little":

  1. Clone the code that define the class in a new unit, call that unit something that let clear it is for cloning that class with some modifications
  2. Use the same class name only if your modifications would be backward compatile (like when additg to TEdid the Align property, use the hack of declaring it as TTheClass=class(TheUnit.TTheClass)), else use a different name
  3. Add such new unit at the end of the uses of interface section

That is it... simple to say, hard work to do on some cases.

I allways recomend using nes classes names, except as on the sample of adding Alignment property to a TEdit.

When use the hack of declaration? When you have a full application already coded and want to add to all TEdit on it the alignment... insetead of creating a new component, adding it to component tools, redefine all forms to not use :TEdit; and use :TMyAlignedEdit... you can just simple add to uses your unit and voila... all TEdit now have such property and IDE inspertor also sees it, etc.

于 2017-04-24T10:01:01.253 回答