I want to limit the access of protected methods to certain inherited classes only.
For example there is a base class like
TBase = Class
Protected
Method1;
Method2;
Method3;
Method4;
End;
I have two classe开发者_Go百科s derived from TBase
TDerived1 = Class(TBase)
//Here i must access only Method1,Method2 and Method3
End;
TDerived2 = Class(TBase)
//Here i must access only Method3 and Method4
End;
Then is it possible to access only Method1, Method2 and Method3 when i use objects of TDerived1 and Method3 and Method4 when i use objects of TDerived2
There's no way to do that. If a method is protected, then all descendant classes have access to it. You might want to rethink your class design if you have two separate sets of functionality that can be divided that easily.
I'd split them, similar to Jeroen's answer:
TBase = class
end;
TBase12 = class(TBase)
protected
procedure Method1;
procedure Method2;
end;
TBase34 = class(TBase)
protected
procedure Method3;
procedure Method4;
end;
TDerived1 = class(TBase12)
end;
TDerived2 = class(TBase34)
end;
From what you describe, this seems to better model your requirements than a "monolithic" base class (like Mason already wrote).
One more way - you can do this using Interfaces...
IBase1 = interface
// press Ctrl+Shift+G here to generate your own sexy GUID
procedure Method1;
procedure Method2;
end;
IBase2 = interface
// press Ctrl+Shift+G here again
procedure Method3;
procedure Method4;
end;
TBase = class(TInterfacedObject, IBase1, IBase2)
public
{ IBase1 }
procedure Method1;
procedure Method2;
{ IBase2 }
procedure Method3;
procedure Method4;
end;
var
B1: IBase1;
B2: IBase2;
begin
B1 := TBase.Create as IBase1;
B2 := TBase.Create as IBase2;
B1.Method1; // works
B1.Method3; // Can't compile
B2.Method3; // works
end;
Seems to me your methods aren't declared in the right place.
If Method1 and Method2 are not called in TBase, and should only be called from TDerived1 and descendents... then those methods should be declared in TDerived1.
If Method1/2 access private fields of TBase, then you should have properties or Getter/setter to those field in TBase.
But unless you give more specific reasons as to why those methods need to be in declared in TBase, I'd say it's just bad design to declare them there.
A solution that works in a similar way to publish private/protected/public properties that works for methods.
So you could do it like this:
unit PropertyAndMethodVisibilityPromotionUnit;
interface
type
TBase = class
private
procedure Method1;
procedure Method2;
procedure Method3;
procedure Method4;
end;
TBase1 = class(TBase)
protected
procedure Method1;
procedure Method2;
end;
TBase2 = class(TBase)
protected
procedure Method3;
procedure Method4;
end;
TDerived1 = class(TBase1)
//Here i must access only Method1 and Method2
end;
TDerived2 = class(TBase2)
//Here i must access only Method3 and Method4
end;
implementation
procedure TBase.Method1;
begin
end;
procedure TBase.Method2;
begin
end;
procedure TBase.Method3;
begin
end;
procedure TBase.Method4;
begin
end;
procedure TBase1.Method1;
begin
inherited;
end;
procedure TBase1.Method2;
begin
inherited;
end;
procedure TBase2.Method3;
begin
inherited;
end;
procedure TBase2.Method4;
begin
inherited;
end;
end.
Notes:
- This only works if
TBase
,TBase1
andTBase2
are in the same unit. - It is a hack working around a potentially weak class design, so be sure you review your class design
--jeroen
ok... Here's a possible way to achieve what you are looking for. I think it requires Delphi 2005 or later though. (Or whatever version that introduced the "Strict Protected|private" visibility)
TBase = Class
Strict Protected
procedure Method1;
procedure Method2;
procedure Method3;
procedure Method4;
End;
TDerived1 = Class(TBase)
Protected
procedure Method1;
procedure Method2;
procedure Method3;
End;
TDerived2 = Class(TBase)
Protected
procedure Method3;
procedure Method4;
End;
TUserClass = class
FImplementer : TDerived1;
end;
And the methods look like this
procedure TDerived2.Method3;
begin
inherited Method3;
end;
But your requirements make me wonder if your method really belongs to your TBase class. Seems they should be static procedure, or maybe class procedure of another class. I don't think they really belong to TBase.
精彩评论