How can I access a hidden member from a derived class? - delphi

I have two classes, one derived from the other. These classes both introduce variables with the same name. The variable in the derived class hides that in the super class.
How can I refer to the super class's variable from a method of the derived class?
type
TClass1 = class
protected
FMyVar: Integer;
end;
TClass2 = class(TClass1)
protected
FMyVar: Integer;
public
procedure Foo;
end;
procedure TClass2.Foo;
begin
//here I want access to FMyVar from TClass1
end;

There's nothing special. Each subclass automatically has access to things from its parent class, except those members that were marked private in the parent.
Sublasses declared in the same unit as their parent have access to members marked private. Use strict private instead to really prevent subclasses from accessing their inherited members.

You can gain access with a cast:
procedure TClass2.Foo;
begin
DoSomething(TClass1(Self).FMyVar);
end;
As a side note, I suggest you reconsider your design. The path you are taking leads to confusion and bugs.

Related

Multiple generation of Obj with a generic class

I'm having some trouble with generics and constructors.
I would like to have a Generic class that can handle (and create) multiple objects of the same class. Moreover, I have some code that I would like to use whatever the specific class actually is.
I thought Generics are a good solution to this, but I'm not quite sure.
type
TMultiBlock<T: IBlock, constructor> = class(TObject)
blocks: array of array of T;
constructor Create(const owner: someClass, const n: integer);
end;
constructor TMultiBlock<T>.Create(const owner: someClass, const n: integer);
var
i: integer;
begin
for i := 0 to n-1 do
T.Create();
end;
The solution above works, but the Create() that is called is not the one of the class T that I give to the Generic.
I know that I can do the Create outside the TMultiBlock class, since I know class T there, as show below:
TM := TMultiBlock<TFinestra>.Create();
for i := 0 to n do
begin
TM.blocks[i] := TFinestra.Create();
end;
Here the class TFinestre is one of the class that I want to use in the Generic. But the thing is that I want to do some common operations on the T element, and these operation will be common to whatever the T type is, so I would like to do them on the TMultiBlock.
IBlock is an interface implemented by each class of type T.
An Interface is, in OOP terms, a pure abstract definition. It can be implemented by lots of different classes. You can't create objects from an interface (unless the interface gives you a method to create an object), you can get an interface from an Object if that object supports it. As all interfaces are implemented by a class then they can do different things, but ultimately what they do is dependent on what the object is, so you are back to having to know the class.
If you want to create the objects you have to know the class of the object you are creating. The interface could provide a method for returning the class of the object which is implementing the interface, allowing you to create more of them, but then you may as well use that class.
If your different types do not have a common ancestor, then you can specify, as you have, that T must support an interface, but you still instantiate the TMutliBLOCK<T> with a class. As interfaces are always implemented by a class then T will always derive from TObject so it will always support Create. The problem is you can't call T.Create unless IBlock includes the definition of Create ...
This means that you can have a TMulitBLOCK and a TMultiBLOCK but each would be holding the objects you have declared for it. If they're not inheriting from a common class then you would not be able to restrict the type of T to that common ancestor.
You can check that the type you are using supports an interface in the constructor, and then restrict to TObject.
TMultiBLOCK<T: class> = class(TObject)
protected
blocks: TArray<T>;
public
constructor Create(AOwner: pSomeObject; nSize: Integer);
end;
constructor TMultiBLOCK<T>.Create(AOwner: pSomeObject; nSize: Integer);
begin
if(not Supports(T, IBlock)) then
raise EInvalidCast.Create('Class '+T.ClassName+' must support IBlock')
else
...
end;
To call the members of IBlock you will need to get an interface pointer for each object. Bear in mind that depending on the implementation in the different implementing classes then when the interface references go out of scope the object may delete itself. To prevent that happening you probably want to store the interface references alongside the objects when you create them so the reference count is held above 0.
If you can organise the code so that all members are derived from a common ancestor then you can restrict your TMultiBLOCK<T> to that common ancestor, rather than a common interface.

override, virtual/dynamic in Delphi constructors

The one with virtual/dynamic
// declare in Child Class
constructor Create; virtual;
constructor TChildClass.Create;
begin
inherited;
end;
The one with override.
// declare in Child Class
constructor Create; override;
constructor TChildClass.Create;
begin
inherited;
end;
The one with nothing
// declare in Child Class
constructor Create;
constructor TChildClass.Create;
begin
inherited;
end;
Are these the same thing? It looks confusing.
Yes, there is a difference, but let's deal with the virtual keyword in more basic OOP terms first, yet still how it applies to Delphi methods.
When you declare a derived (child) class, and implement a method as "override", it means that you're overriding (surprise) the matching method of the base class.
This means that you can write code like this:
var child : TBaseClass;
begin
child := TChildClass.Create; // note that it is stored in TBaseClass variable
child.VirtualMethodDefinedInBaseClassThatHasBeenOverriddenInChildClass;
This will call the method in the child class, even if the variable is defined to be of the base class type. This is the whole purpose of virtual methods, you can access the object through a reference of a more general type, and still call methods that have been written for the particular type of object you're dealing with.
If you have a virtual method in the base class that you chose not to override in the child class, but instead reintroduce, you're effectively replacing it in some cases. Note that in most cases you need to tell the compiler that you really meant to do this, though I'm unsure about what Delphi requires here.
Basically, if your variable is of type TBaseClass, and you call a virtual method on it, that has been reintroduced in the TChildClass, it will still call the method in the base class.
However, if your variable is of type TChildClass, and you call that method on it, you will get the new method instead.
Now, for constructors, in Delphi, it is slightly different.
The point of virtual constructors is to be able to virtually construct objects, and to do that, Delphi also has "class types".
You can say this:
type TClassToUse = class of TBaseClass;
var cls : TClassToUse;
obj : TBaseClass;
begin
cls := TChildClass;
obj := cls.Create;
(note that my Delphi knowledge is a bit rusty here, if anyone spots bugs or glaring problems in the above code, please let me know or just fix it)
Here we store a "class" in a variable, and then ask the class to please construct an object for us. This allows us to switch out which class to create, but we also need to declare the constructors we want to use virtual, otherwise we will have problems.
So in the above code, if you declared the constructor as virtual in TBaseClass, and then override it in TChildClass (which the code is actually using in cls), the overridden constructor is the one that will be used.
If, on the other hand, you don't declare the constructor as virtual, we're back to the base class constructor. Virtual basically means to figure out the right method to execute at runtime, whereas non-virtual will figure it out at compile time.
Reintroduction as described for normal methods above, also works this way.
However, virtual constructors are only used as virtual when used through a class type.
No, static and virtual methods are not the same thing.
And override is a case of virtual method.
http://en.wikipedia.org/wiki/Virtual_function
http://docwiki.embarcadero.com/RADStudio/XE4/en/Methods#Method_Binding
Constructors bring nothing special here - they conform to the same rules as other methods for the question

Delphi Class variable per class

I've added a class variables to the base class of a deep class hierarchy. It's an integer intended to count number of instances created per class type. But I've run into a problem.
Given the example:
TBaseClass = class
private
class var fCreated: integer;
public
class function NewInstance: TObject; override;
end;
TDescendant = class(TBaseClass)
end;
...
class function TBaseClass.NewInstance: TObject;
begin
result := inherited NewInstance;
inc(fCreated);
end;
I assumed that I can use the class var to store the number of instances created per class, but this does not seem to be the case.
Inspecting TBaseClass.fCreated returns same value as TDescendant.fCreated, changing one via inspector changes the other, so it behaves as if fCreated is a single global var.
I expected fCreated to be maintained per class type, isn't that the point ? What am I missing ?
You are missing nothing. Your analysis of how class variables work is correct. A class var is nothing more than a global variable that is scoped by the class.
One simple solution for you is to use a dictionary to count the instances. A more hacky approach is to use a trick of mine that Hallvard Vassbotn blogged about, which (ab)uses the VMT to store class-specific fields. You can read all about it here.
You see TDescendant.fCreated as the same as TBaseClass.fCreated, becuse they are in the same unit, and therefore TDesendant sees the TBaseClass private fields. If you put them into separeted units, this will be over. Of if you declare fCreated not as Prvate, but Strict Private, TDescendant won't see it.

Static classes in Delphi (Win32)

Is it in Delphi (Win32) possible to declare a whole class (not only a function of the class) as static?
Looks like user search for "class functions":
type
TSomeClass = class
class procedure MyFunction(...);
This is like static method, so, call it:
TSomeClass.MyFunction(...);
I assume you mean static classes like in .net (and not "static" as in traditional Delphi/Native) - and the answer to that is no.
I would use an abstract class (not to be confused with an abstract method in a class) to prevent it from being instantiated instead of demoting the constructor to protected:
TMyClass = class abstract
public
class procedure DoStuff; static;
end;
That will enforce the singleton pattern and prevent any instantiations period.
I am not quite sure what you mean by a "static class". You can declare a class, that has only class methods, so these methods can be called without instantiating the class.
TSomeClass.SomeMethod;
Is that what you want?
Not natively.
Depending on what you need it for, if for the purposes of your code, in some use cases you could replace it with a Singleton Pattern object.
For walkthrough on implementing this I'd recommend this guide which, covers almost any version of delphi, but if you're using Delphi 2010 you could also use the new class Constructors/Destructors for improved results.
You could create a class that contains nothing but static methods. If you have to maintain some sort of state, then the state variables should be passed as var parameters. There is no way to "properly" access static variables other than having a set of global variables in the implementation section of the class OUTSIDE the scope of the class, for example:
UNIT TestUnit;
INTERFACE
Type
TStaticClass = Class
public
procedure Foo(var Bar:String); static;
end;
IMPLEMENTATION
var
LastBar : String; // the last bar
LastRes : string; // the last result
Procedure TStaticClass.Foo(var Bar:String);
begin
if Bar <> LastBar then
LastRes := SomeCPUExpensiveProcess(Bar);
LastBar := Bar;
Bar := LastRes;
end;
INITIALIZATION
LastBar := '';
LastRes := SomeCPUExpensiveProcess('');
END.
You can also create a new unit called uDG_Utils for example, define a class, define a global variable for that class and in the initialization and finalization section you manage the class constructor and destructor.
Now all you need to do is call it like mySuperDuperClass.SuperMethod...
EDIT
I have edited this post to remove it. The answer is admittedly bad and deserves the down-votes. I don't want it to remain here to confuse or mislead anyone further.

How to access functions in child classes?

A child class can access protected functions in parent class,but the parent class can't access protected functions in child class.
I'd like to keep both classes as private as possible.The parent class is a form and only once instance is used.All functions in the child class are static,it inherits from the parent class.
How is it possible to access non-public,static methods in the child class(in another unit) from the parent class?
EDIT:
Parent class(First unit):
interface
type
TParent = class
public
procedure Initialize;
protected
procedure Test; virtual;
end;
implementation
procedure TParent.Initialize;
begin
Writeln('Initializing');
Test;
end;
procedure TParent.Test;
begin
end;
Child class(Second unit):
interface
uses
ParentClass;
type
TChild = class(TParent)
protected
procedure Test;override;
end;
implementation
procedure TChild.Test;
begin
Writeln('Test!');
end;
Code(Third unit):
var c:TParent;
begin
try
c := c.Create;
c.Initialize;
c.Free;
Readln;
end;
The output is only "initialing".I tried to debug it,it doesn't reach the child class.
There actually are several ways to do this, in your parent class, create virtual methods which you call but these do not do anything. In your child classes, override these methods. The methods could easily be protected, but they must exist in the parent.
type
TParent = class
protected
procedure SpecialProcessing; virtual;
public
procedure DoWork;
end;
TChild = class(TParent)
protected
procedure SpecialProcessing; override;
end;
procedure TParent.DoWork;
begin
SpecialProcessing;
end;
procedure TParent.SpecialProcessing;
begin
// does nothing, placeholder
end;
procedure TChild.SpecialProcessing;
begin
// do special work here
end;
I purposely did NOT make the TParent.SpeciallProcessing abstract. This could be done, but only if TParent would never get created directly, only decendants would be. An abstract method is one which is NOT implemented but is used as a placeholder for implementation by a later child.
To create an instance you use the following:
var
C : TParent;
begin
// Create as a TChild, which is a TParent decendant
C := TChild.Create;
try
C.DoWork;
finally
C.Free;
end;
end;
What you want to do violates the Liskov Substitution principle in inheritance. There is probably a better way of doing that. What exactly do you want to do?
EDIT:
Why can't you create the object instance from the child class. You can always assign it to a variable of the type of the parent class. This is commonly done in factory patterns.
It is not possible to do this. The whole purpose of having non-public methods in the child class is to prevent classes (other than the child class) from being able to access them. Trying to work around this violates basic object oriented principles.
I'd consider rethinking your design.
I might be missing something obvious to the people who already answered. But I think that it's just a matter of instantiating the right object.
The parent code will call the child code, given the object is an instance of the child class.
Try this
var c:TChild;
begin
c := TChild.Create;
c.Initialize;
c.Free;
end.
or even
var c:TParent;
begin
c := TChild.Create;
c.Initialize;
c.Free;
end.
You can do this by registering the child class with the parent when you create it, using some kind of callback (a cattr on the parent, and the child sets when it's defined).
It's rarely the right thing to do, though. Like others have said, consider a different pattern.
I'm not a delphi coder, but you can set a public static variable on the parent class, and set it from a setup method in the child class.
This makes sense in some situations (wanting to pass messages through to class setup methods on a variety of child classes), but there's probably a better way to do what you need. You might want to make your question more about the problem your code is solving.

Resources