Well,I have a parent class with a nested class declared in the "protected" tab with a protected class variable.In another unit I have a child class,which inherits from the parent class.When I try to access something protected/public from the parent class -it works,but when I try to access something protected from the nested class,it doesnt work.
type
TParent = class(TObject)
protected
class var x:integer;
type
TNested = class(TObject)
protected
class var y:integer;
end;
end;
My code in the child class:
x := 10; //works
y := 10; //undeclarated idenitifier 'y'.
TNested.y := 10; //undeclarated idenitifier 'y'
the declaration of the child class is:
type
TChild = class(TParent);
How do I access y?
y:integer is a protected field of TNested class, ie. can be only used by TNested and it's own inherited classes.
You probably may use TNested from TParent but this is beacause in Delphi you may have greater access than it should be if calling from the same unit. So TParent and TNested are in the same unit, so you may call TNested protected data from TParent. But since TChild is in different unit than TNested, it is impossible.
This will actuall work if TChild and TParent are in the same unit, because of the implicit friendship between classes within the unit.
To access y in your example, you'd need to do one of two things:
Change the scope of y to public (or create a public property for it).
Use y from a nested class that is derived from TNested.
TParent.x := 10;
TParent.TNested.y := 10;
The example you are giving is using a nested class, not inheriting it.
Nested classed can be inherited in subclasses of the declaring class:
TSubParent = class(TParent)
protected
type
TSubNested = class(TNested)
public
class var Z : integer;
end;
end;
Related
I have written this simple code:
type
TTestA = class
strict protected
a: integer;
public
f: integer;
constructor Create(x: Integer);
end;
type
TTestB = class(TTestA)
strict private
c: integer;
end;
I use strict because these classes are in the same unit as the TForm1 class. Since a is protected by definition, it should be accessible only in subclasses, but then why this code doesn't work?
procedure TForm1.Button1Click(Sender: TObject);
var
K: TTestB;
begin
k := TTestB.Create(3);
value = k.a; //I cannot access a
end;
Also, the protected can be useful to create an abstract class. In C++, if I declare a constructor as protected, I cannot create an instance of the object and only subclasses can. Can Delphi do this?
I am having the same problem with the variable and the constructor.
protected access means "accessible in the class and any sub-class".
This means that a in your example will be accessible to methods in class TTestB but this does not extend to consumers of instances of TTestB (or TTestA).
The code in TForm1 is part of a class which is not a subclass of TTestA.
Put another way, TForm1 does not inherit from TTestA and therefore cannot access any private or protected members of k.
The answer is in your own question:
Since a is protected by definition it should be accessible only in subclasses
Regardless of the fact that TForm1 uses a local k variable of type TTestB, since TForm1 itself is not a subclass of TTestA, it does not have access to the k.a member. TTestB is a subclass of TTestA, so internally it has access to a.
This is explained in more detail in Embarcadero's documentation:
Classes and Objects (Delphi): Visibility of Class Members
I need to create a Class like this
unit Classname;
interface
type
TSomeClass = class
public
member1 : SomeType;
member2 : AnotherDataType;
....
function SomeFunction: SomeType; stadcall;external 'ExternalDll.dll';
end;
Can it be done?
How can I declare a external function (stored in a c dll) from a Class in Delphi
I'm using Delphi 7.
Thanks in advance
External functions cannot be part of a class declaration. You need to declare the external function with global scope and arrange that the class's methods then call that external function.
You could create a class with pseudo methods like this:
type
TMyDllClass = class
public
NameOfDllEntryPoint: TFunctionTypeOfDllEntryPoint;
constructor Create;
end;
constructor TMyDllClass.Create;
begin
inherited Create;
LibHandle := LoadLibrary('path\to.dll');
#NameOfDllEntryPoint := GetProcAddress(LibHandle, 'NameOfDllEntryPoint');
end;
MyDllClass := TMyDllClass.Create;
MyDllClass.NameOfDllEntryPoint(some, parameters);
This works fine, I have done it multiple times, e.g. for mitab.dll, libjpeg_turbo.dll and other dlls. The idea is to reduce cluttering the name space with global functions.
Note: For clarity I left out any error handling (e.g. if the DLL cannot be loaded or doesn't have the entry point). In this example this would result in an access violation because the NameOfDllEntryPoint field would not have been initialized.
I saw a code like this the other day:
type
TcxGridTableControllerAccess = class (TcxGridTableController);
TMycxGridDBTableView = class (TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class (TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class (TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class (TMycxGridDBTableView);
TMycxGridDBTableView inherited from TcxGridDBTableView that inherited from TMycxGridDBTableView. Searched for Cyclic Inheritance but only Java results.
What is this called?
Ps: I don't have the full buildable code with me.
The example code doesn't do what you think it does. You see TMycxGridDBTableView being defined as a descendant of TcxGridDBTableView, and then you see TcxGridDBTableView, defined as a descendant of TcxGridDBTableView.
However, the TcxGridDBTableView you see at the top is not the same TcxGridDBTableView that you see later. The first one refers to a class declared elsewhere, in some other unit. The next occurrence is declaring a new class in this unit that happens to have the same base name as the other unit's class.
This technique is known as an interposer class. It's used to introduce a new GetViewDataClass method, but still end up with the same class name. The form that uses controls with that name will use the new version of the class instead of the original version. It's a way to customize a VCL control without having to compile and install a custom package.
What you show is not cyclic inheritance. What happens is that dxSample.TMycxGridDBTableView inherits from a TcxGridDBTableView in another unit, probably cxGridDBTableView.TcxGridDBTableView. And dxSample.TcxGridDBtableView inherits from dxSample.TMycxGridDBTableView.
Your code is equivalent to:
type
TcxGridTableControllerAccess = class(TcxGridTableController);
{ Note: this does NOT inherit from the TcxGridDBTableView defined }
{ a little further on in the source. It inherits from the original }
{ DevEx TcxGridDBTableView. }
TMycxGridDBTableView = class(cxGridDBTableView.TcxGridDBTableView)
protected
function GetViewDataClass: TcxCustomGridViewDataClass; override;
end;
TMycxGridViewData = class(TcxGridViewData)
protected
function GetFilterRowClass: TcxGridFilterRowClass; override;
end;
TMycxGridFilterRow = class(TcxGridFilterRow)
protected
procedure SetValue(Index: Integer; const Value: Variant); override;
end;
TcxGridDBTableView = class(TMycxGridDBTableView);
So the hierarchy is:
cxGridDBTableView.TcxGridDBTableView
|
v
dxSample.TMycxGridDBTableView
|
v
dxSample.TcxGridDBTableView
So dxSample.TMycxGrdiDBTableView does not inherit from dxSample.TcxGridDBTableView, but from cxGridDBTableView.TcxGridDBTableView instead, so there is no so called cyclic inheritance there. The whole misunderstanding comes from the fact that the two classes in the different units have the same name and that the first declaration does not fully qualify the class it is inheriting from.
Now, if someone puts the unit dxSample after cxridDBTableView in his or her uses clause, then dxSample.TCxGridDBTableView is used, instead of the original DevEx class. This is called interposing.
When people want to modify the behaviour of the VCL and FireMonkey, it is not unusual to see interposer classes like
type
TVCLClass = class(OriginalVCLUnit.TVCLClass)
// modifications to the original TVCLClass
end;
or
type
TMyVCLClass = class(OriginalVCLUnit.TVCLClass)
//
end;
TVCLClass = class(TMyVCLCLass);
The code you showed does the latter.
I am creating a class with class constructor
TStaticDynSettings = class
public
class constructor create;
class destructor destroy;
class procedure Reload;
end;
Do all the other method in the class apart from create and destroy need to be a class methods?
I know for sure all the variables need to be a class var else the automatic initialization wont work.
what is the difference in calling the procedure as?..
var StDyn : TStaticDynSettings;`
StDyn.Reload;
and
TStaticDynSettings.Reload;
1 - If you are not planning to create object instances of TStaticDynSettings you can use any of 3 forms:
type
TStaticDynSettings = class
public
procedure Reload1;
class procedure Reload2;
class procedure Reload3; static;
end;
call examples:
procedure Call1;
var Instance: TStaticDynSettings;
begin
Instance.Reload1;
end;
procedure Call2;
begin
TStaticDynSettings.Reload2;
end;
procedure Call3;
begin
TStaticDynSettings.Reload3;
end;
The difference is a hidden argument passed in Reload1 and Reload2 methods and not passed in Reload3.
The hidden argument is a reference to object instance in Reload1 (and not used since you are not creating object instance), and a class reference in Reload2 (which probably also unnecessary in your case, assuming a class reference is known at compile time).
The first form (Reload1) is misleading because it assumes using an object reference and so should be avoided (though it works).
The third form (Reload3) is preferable if you are not using class references that are unknown at compile time.
2 - There is no difference (not counting an overhead of using unnecessary object variable if the first case).
If I have child class,the child class inherits all methods from the parent,but how do I use functions from the child class in the parent class? Is that what abstraction is? How do I accomplish it?
My code:
type
cParent = class(TObject)
private
function ParentFunction:byte;
function ChildFunction:byte;virtual;abstract;
end;
type
cChild = class(cParent)
private function ChildFunction:byte;override;
end;
function cChild.ChildFunction:byte;
begin
Exit(20);
end;
function cParent.ParentFunction:byte;
begin
Exit(10);
end;
var
c:cParent;
begin
c:= cParent.Create;
WriteLn(c.ChildFunction);
Readln;
end.
It compiles file,but I get abstraction exception.
c:= cParent.Create;
WriteLn(c.ChildFunction);
You create an instance of cParent class here. This class does only contain an abstract ChildFunction that can be overridden by other classes. The function is not implemented in cParent, so you get an abstract error.
The code works if you use the cChild class instead, where ChildFunction is implemented:
c:= cChild.Create;
WriteLn(c.ChildFunction);
For clarification, imagine a parent class named GeometricObject with an virtual abstract method CalculateVolume. You can now create child classes like SphereObject or BoxObject that implement CalculateVolume by using the formula for spheres/boxes. But it doesn't make sense to create an instance of GeometricObject and call CalculateVolume.
You create instance of cParent class. This class don't have implementation of childFunction. c must be instance of cChild class.
Correct code:
c := cChild.Create;
WriteLn(c.ChildFunction);
Create the instance using the child class:
c:= cChild.Create;
It seems to me that you have confused inheritance relationships and possessive relationships. If you define a class "cChild" as inherited from class "cParent" then the class "cChild" is a "cParent", it does not mean, that the class "Parent" has access to any child classes. The only way you can call the abstract function "ChildFunction" in the class "cParent" is from another function, e.g. "ParentFunction", but only if the Object itself is not a "cParent":
function cParent.ParentFunction:byte;
begin
Result := ChildFunction * 2;
end;
var
c:cParent;
begin
c:= cChild.Create;
WriteLn(c.ParentFunction);
Readln;
end.
Here, since c is a cChild, ParentFunction correctly calls ChildFunction, which is defined in cChild.
In response to schnaader, regarding CS 101:
"virtual" means the method can be overridden by child classes.
Not only this, but non-virtual functions may happily be overridden by child classes. The difference is very important: when a virtual function is called by the parent class, the CHILD function will be executed. This allows child classes to implement functions that will be called by parent classes without the parent ever knowing anything about them. This is the essence of polymorphism.