7

In one base class, there's a protected procedure. When inheriting that class, I want to hide that procedure from being used from the outside. I tried overriding it from within the private and even strict private sections, but it can still be called from the outside. The Original class is not mine, so I can't change how TOriginal is defined.

Is it possible to hide this procedure in my inherited class? And how?

type
  TOriginal = class(TObject)
  protected
    procedure SomeProc;
  end;

  TNew = class(TOriginal)
  strict private
    procedure SomeProc; override;
  end;
Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • 2
    if you want to hide method of base class from descendant class then you have to declare it in private-section; private methods are visible only from self class; protected methods are visible from class itslef and inherited classes and finally public or published methods are visible for everyone; published is the same as public but this sections is used by delphi IDE to make properties of components visible in object inspector; – teran Feb 22 '12 at 17:56
  • also there are two terms "hiding" and "overriding"; in your example you have to mark `SameProc` in base class as `virtual`; and then you redeclare it in inherited class and mark it as `override` it means overriding; this means that if you create `TNew` and assign its instance to `TOriginal` variable (`var orig := TNew.Create()`) and after that call orig.SomeProc then implementation of TNew.SomeProc will be called; if you will not mark it as `override` then orig.SomeProc equals `TOriginal.SomeProc` also it is useless to lower method visibility because you always can upcast it and call – teran Feb 22 '12 at 18:05
  • 2
    What's stopping code using your derived class from casting references to base class references or assigning them? Gaining access to any "hidden" methods? What you want can not be done. If you feel the urge to do so then the inheritance relations are all wrong. – mghie Feb 22 '12 at 18:13
  • 1
    Why the downvotes? This seems like a reasonable question, conforms to the FAQ and can be answered. Sure, it's a bit misguided (it brakes "OOP") but that can be addressed in an answer! – Cosmin Prund Feb 22 '12 at 18:52
  • The problem is I *don't have control of the base class* as it's part of `VCL`. Revising question to make this clear. – Jerry Dodge Feb 22 '12 at 18:57
  • 2
    @Jerry: I assumed as much. All that means is that you should not inherit that class if you can't live with its interface. Read about the Liskov substitution principle (http://en.wikipedia.org/wiki/Liskov_substitution_principle). Maybe composition would be better than inheritance in your case? – mghie Feb 22 '12 at 19:31
  • @JerryDodge, what's the mysterious base class and what method you'd like to block? The fact that it's a VCL class makes things much worst: Because of how OOP works you *can't* block `TOriginal.SomeProc` for objects that take parameters as `TOriginal`; Because you're dealing with a VCL class, there's a higher chance some code exists that directly deals with your base class and calls `SomeProc` through a variable of the base type! – Cosmin Prund Feb 22 '12 at 19:36
  • Based on the input, I see now it is not possible to hide something any more than it has been exposed. Hidden things can be brought into the picture, but existing things cannot be hidden. – Jerry Dodge Feb 22 '12 at 19:52
  • PS I didn't mention the original *base* class because I'm trying to *depersonalize* the questions I ask; meaning I'm trying to highlight the scope of the question without any mention to any personal naming, usage, etc. I was aimed at the general subject of access levels of class members. – Jerry Dodge Feb 23 '12 at 00:18

2 Answers2

11

Protected methods are already hidden from the outside. (Mostly; see below.) You cannot reduce the visibility of a class member. If the base class declared the method protected, then all descendants of that class may use the method.


In Delphi, other code within the same unit as a class may access that class's protected members, even code from unrelated classes. That can be useful sometimes, but usually to work around other design deficiencies. If you have something that's "really, really" supposed to be protected, you can make it strict protected, and then the special same-unit access rule doesn't apply.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • And using `Class Helpers` it is still possible to access strict protected/private members. – LU RD Feb 22 '12 at 18:26
  • @LURD, as long as there are no `unit helpers` there is no ability to access private members – OnTheFly Feb 22 '12 at 18:48
  • The original class (`TOriginal`) is not my class, so I can't simply change it. Looking further into the original class, I see that `SomeProc` is actually *public* further up in the family, but this class that I'm inheriting has moved it to `protected` which explains why I'm able to access it then. So once something has been exposed, it can't be un-exposed? – Jerry Dodge Feb 22 '12 at 19:01
1

Once exposed you can not hide it but you can do this to spot where it is called in limit way

TOriginalClass = class
public
  procedure Foo;
end;

TNewClass = class(TOriginalClass) 
public
  procedure Foo; reintroduce;
end;

implementation

procedure TNewClass.Foo;
begin
  Assert(False, 'Do not call Foo from this class');
  inherited Foo;
end;

var Obj: TNewClass;
Obj := TNewClass.Create;
Obj.Foo; // get assert message

Will not get Assert error if declared as TOriginalClass
var Obj: TOriginalClass;
Obj := TNewClass.Create;
Obj.Foo; // Never get the assert message
Johan
  • 74,508
  • 24
  • 191
  • 319
APZ28
  • 997
  • 5
  • 4
  • Thanks for the response, and I'm somewhat understanding, but I don't understand where the C-like syntax comes from... This doesn't look like pure Delphi code... – Jerry Dodge Feb 22 '12 at 22:25
  • While I do understand the point, the code is still a little fishy, mainly both classes have `Foo` in *public*? – Jerry Dodge Feb 23 '12 at 15:35