I have 2 classes, ClassA
and ClassB
, each in their own seperate unit, UnitA
and UnitB
.
UnitA
uses UnitB
. This allows ClassA
to call the constructor for ClassB
. Part of ClassB's
functionality however requires the use of ClassA's
methods. I cannot make UnitB
use UnitA
, else this causes a circular reference. What alternative do I have in allowing ClassB
to access ClassA's
methods from within UnitB
?
It depends a lot on how the two classes need to use each other. If one class uses the other in the implementation, but not the interface, then you can move that unit in the uses clause from the interface
section down to the implementation
section instead.
This would work either way around:
UnitA;
interface
uses
Classes, UnitB;
type
TClassA = class(TObject)
end;
...
.
UnitB;
interface
uses
Classes;
type
TClassB = class(TObject)
end;
implementation
uses
UnitA;
...
However, if the interface of both your classes rely on each other, then you have no choice but to put both classes in the same unit (and using forward declarations).
UnitA;
interface
uses
Classes;
type
TClassA = class;
TClassB = class;
TClassA = class(TObject)
end;
TClassB = class(TObject)
end;
...
In rare cases, you might even be able to move an entire class definition down to implementation
. That wouldn't be useful though if you needed to actually use that class elsewhere.
UnitB;
interface
implementation
uses
Classes, UnitA;
type
TClassB = class(TObject)
end;
...
Depending on the complexity, it's also common practice to put commonly shared code in a separate unit of its own. For example constants, record array types, global variables, etc. This common unit shall not use any other of these units.
To expand a little on the previous answer, another possiblity (although definitely less readable) is to refer to an ancestor that both have acess to ( in the extreme case TObject) and then cast in the implementation stage. So
interface
TClassA = class
...
fRefToClassB : TObject; // internal ref
...
procedure UsingBRef( pVar : TObject );
...
end;
implementation
procedure TClassA.UsingClassB
begin
with fRefToClass as TClassB do
...
end;
procedure TClassB.UsingBRef( pVar : TObject );
begin
with pVar as TClassB do
...
end;
Obviously there are many variations on a theme and you would implement is better than this. Again I would emphasise the previous solution is better, but this provides a get out when all else fails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With