I have two classes, a base class and a derived class. My base class has a constructor of this form:
constructor TBaseClass.CreateFromXML(ANode: IXMLNode);
begin
Create;
//Set members from XML
end;
My derived class has a constructor of this form:
constructor TDerivedClass.Create;
begin
FDatabaseID = -1;
end;
My problem is that when I create an object of my derived class using the constructor from the base class [ TDerivedClass.CreateFromXML(Node); ] the Create called at the beginning of the CreateFromXML constructor is not the one from my derived class, but rather the one inherited by my base class from TObject.
Is it possible to get the base class constructor to call my derived class constructor even though it's further "down" the inheritance chain?
Try declaring a constructor Create; virtual; in TBaseClass. Don't forget to mark the "derived" constructor as override.
Related
In this question you see that is possible to create an abstract class adding the abstract keywrod. I am translating a project in Delphi but I see that it allows the creation of an abstract class. This is the code:
type
TCableSPF = class abstract
//code
end;
This is an abstract class of course and I have a lot of subclasses that implement it. By the way I see that is it possible to create an instance of this like;
a := TCableSPF.Create;
When I try to call its methods that are virtual and abstract I get the error and this is ok but can I prevent the creation of the class? Or Delphi allows this by default? thanks for the help
The class abstract is a holdover from the Delphi for .Net days.
For reasons unknown there is no (current) implementation behind this keyword.
If you want to prevent instantiation of an abstract class, this keyword will not help. Instead do the following:
type
TCableSPF = class abstract
//code
strict protected
//Define all constructors for an abstract class as protected.
constructor Create; virtual; reintroduce;
end;
By defining all constructors as protected, only descendent object can access the constructor, other code cannot access the constructor.
Because you reintroducing the virtual constructor, you also cannot instantiate it using:
unit A;
type
TMyAbstractObject = class abstract(TObjectX)
strict protected
constructor Create; virtual; reintroduce;
end;
...
unit B;
TMyClass = class of TObjectX;
AbstractObjectInstance = TMyClass.Create; //Will not work for TMyAbstractObject
Note that you should not declare the constructor override. Instead declare it virtual reintroduce (or just reintroduce if you don't want to allow virtual constructors).
I try to inherit from Tdictionary and somehow the default comparer is lost. This is what I do in essence:
type
TinpVar = class
end;
TinputVars = class(Tdictionary<string,TinpVar>)
end;
TLVRvars = class(TinputVars)
constructor create;
end;
constructor TLVRvars.create;
begin
inherited;
end;
var LVRvars : TLVRvars;
begin
LVRvars:=TLVRvars.create;
With this construction I get an AV when adding a key/value pair to LVRvars. Eventually I found that this can be prevented by changing the constructor of the inherited class to
constructor TLVRvars.create;
begin
inherited create;
end;
I do not understand why I have to do that. Although my problem is solved, I would still like to know.
In your constructor
inherited;
calls the constructor with identical parameter list to your constructor. Your constructor has no parameters, and so inherited calls the do nothing constructor in TObject. Not only have you lost your comparer, but your instance is missing the rest of the necessary steps in construction.
When you replace it with
inherited Create;
the compiler instead performs normal method resolution. It looks up the class ancestor list and calls the first method which it can. In that case this is:
constructor Create(ACapacity: Integer = 0); overload;
Hence your instance is properly created.
The documentation is here: http://docwiki.embarcadero.com/RADStudio/en/Methods#Inherited
Key excerpts are:
If inherited is followed by the name of a member, it represents a normal method call
and
When inherited has no identifier after it, it refers to the inherited
method with the same name as the enclosing method or, if the enclosing
method is a message handler, to the inherited message handler for the
same message. In this case, inherited takes no explicit parameters,
but passes to the inherited method the same parameters with which the
enclosing method was called. For example:
inherited;
occurs frequently in the implementation of constructors. It calls the
inherited constructor with the same parameters that were passed to the
descendant.
It's pretty weird isn't it. On the face of it, it seems astonishing that different methods are called. The key point though is that plain inherited leads to exact matching of parameter lists. And your method has no parameters.
On the other hand inherited Create is a standard method call. In that latter case, you end up calling a method with one parameter, using the default value for that parameter. So whilst it looks like you are calling a parameterless constructor you are not. You are passing one parameter, ACapacity, and a value of 0.
The comparator is a object that need to be created itself. If you had no constructor in your descended class I would expect the default constructor to be created because you would be implicitly calling the inherited constructor. If you create your own constructor you should always called the inherited Create (in my opinion) to allow the ancestor to do its work - in this case creating default comparator.
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.
If I write
type
MyClass = class of TMyClass;
...
Obj := MyClass.Create;
the correct constructor (the one in TMyClass) is called.
If I write
var
ClassVar : TClass;
...
ClassVar := TMyClass;
Obj := ClassVar.Create;
only the TObject constructor is called.
Why? What's the difference between the two versions? Can I force the TMyClass constructor call in the second scenario?
TClass is declared as "Class of TObject" in system.pas. What constructor gets called is decided at compile-time, and all the compiler knows is what base class you're using. It doesn't know what the value of the variable will be when it runs, so it has to default to the base class. If you're using a TClass, then your base class is TObject.
If you're using a class variable, I assume you have some sort of heirarchy and you're trying to implement a factory. If you want to make sure the right constructor gets called based on the value of a class variable at runtime, not something contained in your code at compile time, you need a virtual constructor.
type
TMyBaseObject = class(TObject)
public
constructor Create; virtual;
end;
TMyClass = class of TMyBaseObject;
Use a TMyClass instead of a TClass as your class variable, and now the compiler will generate a call to TMyBaseObject.Create, which is virtual. Make sure all your derived classes override the base constructor, and you'll end up calling the right one at runtime.
TObject.Create is not virtual, you need to declare ClassVar as a classtype of a class with a virtual constructor.
I would suggest you look into overriding the AfterConstruction method that's introduced by the TObject to make polymorphism like this work.
Each class definition can introduce a new constructor, with it's own set of parameters. A class variable only knows of the constructor if the base class it's a variable for. This is all possible because a constructor is neither virtual nor overridden. You could flag the constructor virtual on your base-class, and flag all descending classes override, which blocks the parameter list. (I think if you forget 'override' the compiler warns your new constructir hides the virtual one.)
Or descend it from TComponent, which already have a virtual constructor.
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.