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.
Related
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.
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.
I'm writing a class with some virtual/abstract procedures which I expect to get overridden. However they might not be overridden as well, which is also fine. The problem is finding out whether one of these procedures was actually overridden or not. If they're not overridden, I shouldn't try to call those procedures, and need to go about something different instead. If I try to call one of them and isn't overridden, I get Abstract Error.
Is there a way I can detect whether these procedures were overridden or not?
Here's a sample of how they're declared:
type
TMyClass = class(TObject)
protected
procedure VProc; virtual;
procedure VAProc; virtual; abstract;
end;
You can do something like this. Note that I've removed "abstract". It may work with "abstract" in place, but I haven't tried that.
type
TMyClass = class(TObject)
protected
procedure VProc; virtual;
procedure VAProc; virtual; //abstract;
end;
function GetVAProcAddress(Instance: TMyClass): pointer;
var
p: procedure of object;
begin
p := Instance.VAProc;
result := TMethod(p).Code;
end;
//in one of the TMyClass methods you can now write:
if GetVAProcAddress(self) <> #TMyClass.VAProc then
I think this is the wrong approach, it smells really really bad.. Some suggestions:
Use non-abstract methods that do what you want to do when they are not overridden.
Use events instead of methods. It's easy to check whether they have been assigned.
A method that may or may not be overridden is not an abstract method, it is merely virtual.
An abstract method is one that has no base implementation and for which an implementation must be provided by a descendant.
In your case, simply declare them as virtual and provide them with the NO-OP (No operation) default implementation that your design dictates:
type
TMyBaseClass = class
protected
procedure SomeProc; virtual;
end;
procedure TMyBaseClass.SomeProc;
begin
// NO-OP
end;
Note - this illustrates my own personal convention of documenting a deliberate NO-OP, rather than just leaving an empty implementation.
Any shennanigans you go through to attempt to detect whether a declared abstract method has been overridden or not and to call it - or not - on the basis of that test is likely to cost more time than simply calling a NO-OP implementation. Plus, should you ever need to introduce an implementation in that base class you don't have to change the method from abstract to non-abstract (possibly disrupting those "detection" circuits you had w.r.t that method, and certainly rendering their cost as nothing but pure overhead).
Use RTTI to get the method address of the virtual method in question for the class in questions. Compare it to the method address for the same method of the base class. If it is not the same, then the method was overriden.
If you got a line code like this:
lObj := TMyClass.Create;
you will notice that the compiler will output a warning saying that you are constructing instance of 'TMyClass' containing abstract method TMyClass.VAProc.
Rant: Should I call "inherited" in the constructor of a class derived from TObject or TPersistent?
constructor TMyObject.Create;
begin
inherited Create; // Delphi doc: Do not create instances of TPersistent. Use TPersistent as a base class when declaring objects that are not components, but that need to be saved to a stream or have their properties assigned to other objects.
VectorNames := TStringList.Create;
Clear;
end;
Yes. It does nothing, true, but it's harmless. I think there is value in being consistent about always calling the inherited constructor, without checking to see if there is, in fact, an implementation. Some will say that it's worth calling inherited Create because Embarcadero might add an implementation for TObject.Create in the future, but I doubt this is true; it would break existing code which does not call inherited Create. Still, I think it is a good idea to call it for the reason of consistency alone.
I always do this.
If you are refactoring and move code to a common ancestor, calling the inherited Create has the following advantages:
If the common ancestor has a constructor, you can't forget to call it.
If the common ancestor has a constructor with different parameters, the compiler warns you for this.
You can also override "procedure AfterConstruction". This procedure is always called, no matter what kind of constructor.
public
procedure AfterConstruction; override;
end;
procedure TfrmListBase.AfterConstruction;
begin
inherited;
//your stuff, always initialized, no matter what kind of constructor!
end;
For example: if you want to create an object with a different constructor than the normal TObject.Create, such as TComponent.Create(AOwner) or a custom (overloaded) constructor, you can get problems because your override is not called and (in this case) your "VectorNames" variable will be nil.
I call it, except when i need a very optimized constructor.
I'm writing some software that targets two versions of very similar hardware which, until I use the API to initialize the hardware I'm not able to know which type I'll be getting back.
Because the hardware is very similar I planned to have a parent class (TParent) that has some abstract methods (for where the hardware differs) and then two child classes (TChildA, TChildB) which implement those methods in a hardware dependent manner.
So I would first instantiate an object of TParent check what kind it is then cast it to the correct child.
However when I do this and call one of the abstract methods fully implemented in the child class I get an EAbstractError.
e.g:
myHardware:=TParent.Create();
if myHardware.TypeA then
myHardware:=TChildA(myHardware)
else
myHardware:=TChildB(myHardware);
myHardware.SomeMehtod();
I'm assuming that I can't cast a Parent Class to a child class, and also that there's probably a better way of doing this. Any pointers?
You need a factory method to return you the correct class depending on the Type of hardware you are using...
function CreateHardware(isTypeA: Boolean): TParent;
begin
if IsTypeA then Result := TChildA.Create
else Result := TChildB.Create;
end;
...
var
myHardware: TParent;
begin
myHardware := CreateHardware(True);
myHardwarde.SomeMethod;
end;
... or you could use the State pattern.
Common in either approach is that your TParent class does not has the knowledge to determine the type of hardware.That knowlegde is transfered into the factory method, caller of the factory method, factory itself or state class.
Thanks to Binary Worrier and Mghie for pointing me in the right direction in this instance. The answer given by Lieven would be the easier way in cases where minimising the initialization of the hardware wasn't an issue.
The pImpl idiom is discussed elsewhere on SO
Here is how I understand the implementation in pseudo-delphi-code (note I've not bothered with public/private distinctions for this):
class TParent
procedure SomeMethod(); abstract;
end;
class TChildA (TParent)
procedure SomeMethod(); override;
end;
class TChildB (TParent)
procedure SomeMethod(); override;
end;
class THardware
HardwareSpecficMethods: TParent;
procedure SomeMethod;
constructor Create();
contrsuctor THardware.Create();
begin
InitializeHardware();
If Hardware.TypeA then
HardwareSpecificMethods:=TChildA.Create()
else
HardwareSpecificMethods:=TChildB.Create();
end;
procedure THardware.SomeMethod();
begin
HardwareSpecificMethods.SomeMethod();
end;
end; {class THardware}
You're right, you can't and shouldn't cast from base class to derived class.
I'm assuming you don't want to have the Child object re-run the Parent constructor?
If so . . .
Remove the Parent/Child relationship as it stands, you will have only one Hardware class.
For the specific ChildA and ChildB functionality, create a new inheritance pattern, so that you have an ISpecificHardwareTasks interface or base class, and two derived classes (SpecificA & SpecificB).
When Hardware is constructing it's self, and it gets to the point where it knows what type of hardware it's working with, it then creates an instance of SpecificA or SpecificB). This instance is private to Hardware.
Hardware exposes methods which wrap the ISpecificHardWareTasks methods (it can even implement that interface if that makes sense).
The Specific classes can take a reference to the Hardware class, if that's necessary (though I don't know if you have access to the this pointer in a constructor, my Delphi is getting rusty)
Hope these ramblings helped somewhat.