Johan
Johan

Reputation: 76670

Must I define both the forward declaration and the interface of a class in the same section?

I have a class that I want to keep private, because I only use it in the implementation section. However it is used by a class that is declared public in the interface section.

Is there a way to do something like this:

unit x;

interface

  type
    TPrivate = class;  //forward declaration

    TPublic = class(TSomething)
    private
      FPrivate: TPrivate;
      procedure DoStuffWithFPrivate;
    public
      //...
    end;

 implementation

 type
   TPrivate = class(TObject)
     procedure Test;
   end;

Obviously the above code gives an error:

[dcc32 Error] UnitX.pas(27): E2086 Type 'TPrivate' is not yet completely defined

I don't want to resort to cheap tricks like:

FPrivate = TObject
....
procedure TPublic.DoStuffWithFPrivate;
begin
  TPrivate(FPrivate).Test;

Is there a way to do what I want without having to spill TPrivate's internal details in the interface?

I know it's possible to declare TPrivate as a strict private sub type of TPublic, however I don't like the pollution of the interface section this gives.
Is there a way to keep TPrivate out the of interface section (as much as possible) whilst maintaining type safety?

Upvotes: 1

Views: 1418

Answers (2)

J...
J...

Reputation: 31433

I'm not sure what exactly your definition of "pollution" is as regards the interface section, but if it's just a matter of keeping it from drowning your TPublic class definition with noise then one option might be simply inheritance :

TBasePublic = class(TSomething)
  private
    type
      TPrivate = class
        // ...
        // ... keep TPrivate definition separate
      end;
end;

TPublic = class(TBasePublic)
  private
    FPrivate : TPrivate;
end;

This would even allow you to define TPrivate in a completely different unit if segregation is your goal.

Upvotes: 2

Uwe Raabe
Uwe Raabe

Reputation: 47758

As long as TPrivate is not used anywhere in the interface of TPublic besides the field declaration (f.i. as a methods parameter type) you can use a local class helper to achieve this.

Note: FPrivate is not a good name for that field!

interface

type
  THiddenActual = class
  end;

  TPublic = class
  private
    FActual: THiddenActual;
    procedure DoStuffWithFPrivate;
  public
  end;

implementation

type
  TActual = class(THiddenActual)
  public
    procedure Foo;
  end;

type
  TPublicHelper = class helper for TPublic
  private
    function GetActual: TActual;
    procedure SetActual(const Value: TActual);
  public
    property Actual: TActual read GetActual write SetActual;
  end;

procedure TActual.Foo;
begin
end;

function TPublicHelper.GetActual: TActual;
begin
  Result := FActual as TActual;
end;

procedure TPublicHelper.SetActual(const Value: TActual);
begin
  FActual := Value;
end;

procedure TPublic.DoStuffWithFPrivate;
begin
  Actual.Foo;
end;

OK, it is merely a little variance of that cheap trick, but what are the alternatives? You have to take what is available, don't you?

Upvotes: 4

Related Questions