As we saw earlier, it is possible to gain write access to a read-only property, or rather to its backing field (am talking about native code Delphi here, Win32 and Kylix, - the situation is quite a bit stricter and cleaner in .NET land). You can promote protected properties to public or published to gain access to them, but there is no corresponding promotion syntax for fields or methods. Often you absolutely need to call a protected method of some class - most often method in a VCL component or a 3rd party utility class. This is usually the sign of a badly design class. The author didn't think that application level code would need access to the method. A mock-up example would be:
unit Utility;
interface
type
TUtility = class
protected
procedure Useful;
public
constructor Create;
procedure Boring;
end;
We want to call the protected Useful method, but all we got access to is the public Boring method. Typical, right? ;) If you are lucky, you have control over the type of the instance you are using, and can write your own descendent that promotes the method the clean way, like this:
type
TMyUtility = class(TUtility)
public
procedure Useful;
end;
procedure TMyUtility.Useful;
begin
inherited Useful;
end;
Now you can use TMyUtility instead of TUtility and you'll have the Useful method available as a public method. A final twist is to use the same class name, like this:
unit MyUtility;
interface
uses
Utility;
type
TUtility = class(Utility.TUtility)
public
procedure Useful;
end;
Now you only need to add the MyUtility reference in the uses clause after the Utility reference. However, sometimes you cannot control the type of the instance used - it is created inside a body of 3rd party code, for instance.
As many experienced Delphi programmers will know, you can easily gain access to the protected members of a class instance, simply by casting the instance to a descendent class type declared in the same unit as the cast-expression. For instance, to call the protected Useful method of an instance of the TUtility class you can just:
type
TUtilityEx = class(TUtility)
end;
procedure Foo(Instance: TUtility);
begin
Instance.Useful;
TUtilityEx (Instance).Useful;
end;
The way the Delphi visibility directives work, all code in the same unit as the declared class will gain full public access to all members. It is a kind of implicit friend concept as known from C++.
Thanks to the ingeniousness of Borland's compiler developers this common hack even works in .NET with Delphi 8 - as long as the caller and method is in the same assembly - it does not work across assemblies, because protected maps to the family-or-assembly method attribute in the CLR.
One very prominent component vendor even routinely hides away truly useful (and sometimes essential) methods of their component and helper classes into the protected section, seemingly only in an attempt to hide complexity from naïve users. Then in all their own units that need access to the methods, they turn around and perform this local-descendent-cast hack and their own classes. Shudder! This hack should only be used to get access to other people's code, and not used between your own units!
Interestingly, the compiler only uses the local hack-class to get access to the protected method. Although the TUtilityEx class is mentioned in the source code, nothing from that class (the VMT, RTTI, classname info etc.) is needed or referenced in the compiled code, so the smart linker removes it from the executable code. Otherwise this hack would be very expensive with regards to code-size.
Thanks again, Danny & co!