Consider this class:
unit u_myclass;
interface
type
TMyClass = class
public
class function Foo : Integer;
function Foo : Integer;
end;
implementation
{ TMyClass }
class function TMyClass.Foo: Integer;
begin
Result := 10;
end;
function TMyClass.Foo: Integer;
begin
Result := 1;
end;
end.
I want to use a class function and an instance function with the same name.
Sadly Delphi doesn't like this and the compiler barfs these errors:
[DCC Error] u_myclass.pas(9): E2252 Method 'Foo' with identical parameters already exists
[DCC Error] u_myclass.pas(20): E2037 Declaration of 'Foo' differs from previous declaration
[DCC Error] u_myclass.pas(9): E2065 Unsatisfied forward or external declaration: 'TMyClass.Foo'
My Question: is this possible or is this simply a language limitation (And I need to rename one of the 2 methods)?
It's not possible to give use the same name for an instance method and a class method. That this is not allowed is that the compiler cannot distinguish between them in some scenarios.
For instance, if you write:
procedure TMyClass.Bar;
begin
Foo;
end;
then the compiler cannot determine whether or not you wish to call the class method or the instance method.
The only solution I found is to use overload and different parameters:
unit u_myclass;
interface
type
TMyClass = class
public
class function Foo(A : Integer) : Integer; overload;
function Foo : Integer; overload;
end;
implementation
{ TMyClass }
class function TMyClass.Foo(A: Integer): Integer;
begin
Result := A;
end;
function TMyClass.Foo: Integer;
begin
Result := 1;
end;
end.
Related
I came up with the following for an easy to expand "bit bucket":
unit BitBucket;
interface
type TBitBucket = class
private
class procedure ThrowAway<T>(value: T); static;
public
class property Integer: Integer write ThrowAway;
class property String_: String write ThrowAway;
class property Extended: Extended write ThrowAway;
class property Boolean: Boolean write ThrowAway;
end;
implementation
class procedure TBitBucket.ThrowAway<T>(value: T);
begin
end;
end.
However, although there's no squiggly underlines in the IDE, it won't compile, with the following errors:
[dcc32 Error] BitBucket.pas(9): E2008 Incompatible types
[dcc32 Error] BitBucket.pas(10): E2008 Incompatible types
[dcc32 Error] BitBucket.pas(11): E2008 Incompatible types
[dcc32 Error] BitBucket.pas(12): E2008 Incompatible types
Is there a trick I'm missing that will make this compile? I've tried specifying the generic type argument to ThrowAway, but that causes even more errors. The obvious alternative is to write a ThrowAway method for every type, but that would quickly lead to a lot of code to do effectively nothing.
For those wondering why, in delphi, you can use a compiler switch to prevent use of functions without assigning their return value for compatibility with older code. With a BitBucket you can say BitBucket.Integer := FunctionThatHasSideEffectsAndReturnsAnInteger(...);, without having to create a new variable. I also think it's just funny.
You are confusing a generic with a variant. You need something like this:
unit BitBucket;
interface
type
TBitBucket<T> = class
private
class procedure ThrowAway(const Value: T); static;
class var FVar: T;
public
class property MyProperty: T read FVar write ThrowAway;
end;
implementation
class procedure TBitBucket<T>.ThrowAway(const Value: T);
begin
FVar := Value;
end;
end.
The type is not decided until runtime when you access it i.e
TBitBucket<Integer>.MyProperty := 2;
This is the shortest solution i could come up with
type TBitBucket = class
class var ThrowAway: variant;
end;
Usage
type test = class
procedure Test;
end;
implementation
{ test }
procedure test.Test;
begin
TBitBucket.ThrowAway := 'AString';
TBitBucket.ThrowAway := 1;
TBitBucket.ThrowAway := 1.1234;
TBitBucket.ThrowAway := true;
end;
Tvalue example
And here a example with TValue instead from system.RTTI allowing to put objects into the bucket
type TBitBucket = class
class var ThrowAway: Tvalue;
end;
type test = class
procedure Test;
end;
implementation
{ test }
procedure test.Test;
begin
TBitBucket.ThrowAway := 'AString';
TBitBucket.ThrowAway := 1;
TBitBucket.ThrowAway := 1.1234;
TBitBucket.ThrowAway := true;
TBitBucket.ThrowAway := TObject.Create;
end;
I am trying to create a class that implements an interface but I get these errors:
[dcc32 Error] dl_tPA_MailJournal.pas(10): E2291 Missing implementation of interface method IInterface.QueryInterface
[dcc32 Error] dl_tPA_MailJournal.pas(10): E2291 Missing implementation of interface method IInterface._AddRef
[dcc32 Error] dl_tPA_MailJournal.pas(10): E2291 Missing implementation of interface method IInterface._Release
[dcc32 Fatal Error] MainUnit.pas(8): F2063 Could not compile used unit 'dl_tPA_MailJournal.pas'
The code is:
unit dl_tPA_MailJournal;
interface
uses
Windows,
Generics.Collections,
SysUtils,
uInterfaces;
type
TtPA_MailJournal = class(TObject, ITable)
public
function GetanQId: integer;
procedure SetanQId(const Value: integer);
function GetadDate: TDateTime;
procedure SetadDate(const Value: TDateTime);
function toList: TList<string>;
constructor Create(aId : Integer; aDate : TDateTime);
private
property anQId : integer read GetanQId write SetanQId;
property adDate : TDateTime read GetadDate write SetadDate;
end;
implementation
{ TtPA_MailJournal }
constructor TtPA_MailJournal.Create(aId : Integer; aDate : TDateTime);
begin
SetanQId(aId);
SetadDate(aDate);
end;
function TtPA_MailJournal.GetadDate: TDateTime;
begin
Result := adDate;
end;
function TtPA_MailJournal.GetanQId: integer;
begin
Result := anQId ;
end;
procedure TtPA_MailJournal.SetadDate(const Value: TDateTime);
begin
adDate := Value;
end;
procedure TtPA_MailJournal.SetanQId(const Value: integer);
begin
anQId := Value;
end;
function TtPA_MailJournal.toList: TList<string>;
var
aListTable: TList<TtPA_MailJournal>;
aTable: TtPA_MailJournal;
aListString: TList<String>;
begin
aTable.Create(1,now);
aListTable.Add(aTable);
aTable.Create(2,now);
aListTable.Add(aTable);
aListString.Add(aListTable.ToString);
Result := aListString;
end;
end.
And the interface is:
unit uInterfaces;
interface
uses
Generics.Collections;
type
ITable = Interface
['{6CED8DCE-9CC7-491F-8D93-996BE8E4D388}']
function toList: TList<string>;
end;
implementation
end.
The problem is that you use TObject as the parent for your class. You should use TInterfacedObject instead.
In Delphi, every interface inherits from IInterface at therefore has, at least, the following 3 methods:
_AddRef
_Release
QueryInterface
You must implement these 3 methods, either by implementing them yourself or by inheriting from a base object that includes these methods.
Because you inherit from TObject, but you are not implementing these 3 methods, you get a compilation error. If you read the compiler error, you will see that it actually spells out this omission for you.
TInterfacedObject has already implemented these methods for you.
Other base objects that implement IInterface (aka IUnknown) are: TAggregatedObject and TContainedObject. However these are special purpose vehicles, only to be used if you really know what you're doing.
Change the definition of your class to
TTPA_MailJournal = class(TInterfacedObject, ITable)
And your code will compile.
See Delphi basics for more info.
I have a base class test define below
type
Tinfo = procedure of object;
Test = class(TObject)
public
procedure Add ( const a : Tinfo ); reintroduce ;
end;
procedure Test.Add(const a: Tinfo);
begin
Writeln('base class add function');
// dosomething more
end;
and I have a derived generic class from this base class
TTesting<T> = class(Test)
public
procedure Add ( const a : T ); reintroduce ;
end;
and I am typecasting T to Tinfo but it gives me the error
procedure TTesting<T>.Add(const a : T );
begin
inherited Add(Tinfo(a) ); // gives me error here
end;
is there any way I can implement this?
First your cast is wrong, you obviously want to cast a and not T.
However if you want to type cast on a procedure of object which is a type that cannot be polymorphic in any way it makes no sense to put that into a generic type at all.
What should T be? It only can be a TInfo in your code.
If you however want T to be any event/method type you should store a TMethod in your base class and then work with that in your generic class. But remember that you cannot have a constraint that limits T to be an event type. So you might check that in your constructor.
type
PMethod = ^TMethod;
Test = class(TObject)
public
procedure Add(const a: TMethod ); reintroduce ;
end;
procedure Test.Add(const a: TMethod);
begin
Writeln('base class add function');
// dosomething more
end;
type
TTesting<T> = class(Test)
public
constructor Create;
procedure Add(const a: T); reintroduce ;
end;
constructor TTesting<T>.Create;
begin
Assert(PTypeInfo(TypeInfo(T)).Kind = tkMethod);
inherited Create;
end;
procedure TTesting<T>.Add(const a: T);
begin
inherited Add(PMethod(#a)^);
end;
This question already has answers here:
Two classes with two circular references
(2 answers)
Closed 9 years ago.
I would like to pass "self" as parameter to a method of another class (in a different unit). However the type of the first class is unknown in the second one, because I can't put the first unit into the uses section of the second unit. So I define the parameters type as pointer but when I try to call a method from the first class the Delphi 7 parser tells me that the classtyp is required.
So how should I solve this problem?
By making the class known in the implementaion part you can cast the given reference.
unit UnitY;
interface
uses Classes;
type
TTest=Class
Constructor Create(AUnKnowOne:TObject);
End;
implementation
uses UnitX;
{ TTest }
constructor TTest.Create(AUnKnowOne: TObject);
begin
if AUnKnowOne is TClassFromUnitX then
begin
TClassFromUnitX(AUnKnowOne).DoSomeThing;
end
else
begin
// ....
end;
end;
end.
I like the interface approach for this type of problem. Unless your units are very tightly coupled, in which case they should probably share a unit, interfaces are tidy ways of exchanging relevant parts of classes without having to have full knowledge of each type.
Consider :
unit UnitI;
interface
type
IDoSomething = Interface(IInterface)
function GetIsFoo : Boolean;
property isFoo : Boolean read GetIsFoo;
end;
implementation
end.
and
unit UnitA;
interface
uses UnitI;
type
TClassA = class(TInterfacedObject, IDoSomething)
private
Ffoo : boolean;
function GetIsFoo() : boolean;
public
property isFoo : boolean read GetIsFoo;
procedure DoBar;
constructor Create;
end;
implementation
uses UnitB;
constructor TClassA.Create;
begin
Ffoo := true;
end;
function TClassA.GetIsFoo() : boolean;
begin
result := Ffoo;
end;
procedure TClassA.DoBar;
var SomeClassB : TClassB;
begin
SomeClassB := TClassB.Create;
SomeClassB.DoIfFoo(self);
end;
end.
and notice that TClassB does not have to know anything about TClassA or the unit that contains it - it simply accepts any object that abides by the IDoSomething interface contract.
unit UnitB;
interface
uses UnitI;
type
TClassB = class(TObject)
private
Ffoobar : integer;
public
procedure DoIfFoo(bar : IDoSomething);
constructor Create;
end;
implementation
constructor TClassB.Create;
begin
Ffoobar := 3;
end;
procedure TClassB.DoIfFoo(bar : IDoSomething);
begin
if bar.isFoo then Ffoobar := 777;
end;
end.
Is there some trick how to get pointer of a member function in Lazarus / delphi?
I have this code which won't compile.... Error is
in Delphi:
variable required
in Lazarus:
Error: Incompatible types: got "<procedure variable type of function(Byte):LongInt of object;StdCall>" expected "Pointer"
The code:
TClassA = class
public
function ImportantFunc(AParameter: byte): integer; stdcall;
end;
TClassB = class
public
ObjectA: TClassA;
ImportantPtr: pointer;
procedure WorkerFunc;
end;
function TClassA.ImportantFunc(AParameter: byte): integer; stdcall;
begin
// some important stuff
end;
procedure TClassB.WorkerFunc;
begin
ImportantPtr := #ObjectA.ImportantFunc; // <-- ERROR HERE
end;
Thanks!
A member function cannot be represented by a single pointer. It needs two pointers, one for the instance and one for the code. But that's implementation detail and you just need to use a method type:
type
TImportantFunc = function(AParameter: byte): integer of object; stdcall;
You can then assign ImportantFunc to a variable of this type.
Since you are using stdcall I suspect you are trying to use this as a Windows callback. That's not possible for a member function. You need a function with global scope, or a static function.
type
TImportantFunc = function(AParameter: byte): integer of object;stdcall;
ImportantPtr: TImportantFunc;
procedure TClassB.WorkerFunc;
begin
ImportantPtr := ObjectA.ImportantFunc; // <-- OK HERE
end;
ObjectA.ImportantFunc is not a memory location, so address operator # can't be applied to it - hence compiler error. It is 2 pointers, #TClassA.ImportantFunc (method code) and ObjectA (Self argument). An answer to your question depends on what you really need - code pointer, Self, both or none.
If you need just to scope a function name use static class method
TClassA = class
public
class function ImportantFunc(Instance: TClassA; AParameter: byte): integer;
stdcall; static;
end;