How to override an inherited property?

14,214

Solution 1

Property getters and setters can be virtual, and then overridden by inheriting classes, see below for your example updated. There's one caveat with you're example code and that's you're trying to change the type of the property, which is not allowed. I would advise you check for Value is TExItems in TExMyClass.SetItems but use the inherited Items property and cast to TExItems in all methods of TExMyClass and further inheritants.

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;

Solution 2

Properties cannot be virtual, so they cannot be overridden. They can be hidden, in that within the context of TExMyClass, references to Items will resolve to the property declared in that class, not the one declared in the ancestor.

If you have something whose static (declared, compile-time) type is TMyClass, Items will always refer to the one from that class, even if its run-time type is TExMyClass.

You could declare SetItems as protected and virtual in the base class, and then override it in the descendant instead of declaring a whole new property that happens to have the same name.

Solution 3

You can implement and override methods getItem and setItem;

Implement property Item only for TMyClass

property Items: TItems read getItems write setItemps;

For TMyClass:

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

For 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;

so, TExMyClass.items.className = TExItems !

Solution 4

Technically, you can't override a property, but you can mimic override in several ways. See for example this answer for the most basic manners.

Now I do not have the code for TAdvSmoothDock so the rest is just guessing. When the property getter and setter of TAdvSmoothDock.Items are virtual, you could override them. But in more advanced components, and I suppose the ones from TMS are, then there is a good chance of TAdvSmoothDock having a protected CreateItem method which is called whenever there is need of a new item which could be overriden. If that is the case, then you should implement it like:

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

And use it like:

TKHAdvSmoothDockItem(AKHAdvSmoothDock.Items[I]).ImageIndex := ...
Share:
14,214
user1512094
Author by

user1512094

Updated on June 04, 2022

Comments

  • user1512094
    user1512094 almost 2 years

    I have a class (TMyClass) which have a property (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.
    

    The new "Items" property is inherited from TItems but when I installed the component the new property of TExItems which is "NewProb" did not appear and it looks like the "Items" property is still TItems not TExItems...how to override it?

    Thanks

    Modification : Here is the Real code

    type 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;
    

    Regards.

  • user1512094
    user1512094 almost 12 years
    Thanks for this great reply but in the TExMyClass Class the Setter procedure "SetItems" takes Value from TItems...I want it to take TExItems ? when I changed its (Value parameter) type from TItems to TExItems the compiler gave me the following error : [DCC Error] xxxxxx.pas(34): E2037 Declaration of 'SetItems' differs from previous declaration how to fix this error?
  • Stijn Sanders
    Stijn Sanders almost 12 years
    Like I said, changing the property type when inheriting is not allowed. Checking the type when setting and using Items as TExItems should work though.
  • user1512094
    user1512094 almost 12 years
    Thank you very much for the example! it is very important to read such examples before working with properties.... I was searching and I found something maybe i would help me but i need more explanation here is my question : cannot I use the "reintroduce" instead of "Override"? for the setter and getter?
  • NGLN
    NGLN almost 12 years
    You could, but it is a bad idea because it would break inheritance: i.e. when the ancestor calls the setter or getter, yours wouldn't be called.
  • thewaywewere
    thewaywewere almost 7 years
    Welcome to SO!. Your reply does not look like a good answer to the question. Once you have sufficient reputation you will be able to comment on any post. Also check this what can I do instead.
  • Franco Michel Almeida Caixeta
    Franco Michel Almeida Caixeta about 3 years
    A good solution, but if the parent class is in units other than the daughter, the virtual property and the override must be in protected to work.