Delphi 'private' clause (directive) does n

2019-08-02 11:50发布

问题:

I'm trying to check if my private procedures are really private. But it works the way it shouldn't.

Please help me, maybe I missed something about how the incapsulation should work.

This code should not work. I guess. But it works.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
    tmyclass = class
    private
      procedure one;
    end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure tmyclass.one;
begin
  ShowMessage('1');
end;

procedure TForm1.Button1Click(Sender: TObject);
var myclass:tmyclass;
begin
  myclass.one;
end;

end.

Thank you. (Delphi-7, Win7 x64).

回答1:

private is for a unit.

With more recent version of Delphi, you can use strict private to get the expected behavior.



回答2:

The meaning of private is clearly documented:

Private, Protected, and Public Members

A private member is invisible outside of the unit or program where its class is declared. In other words, a private method cannot be called from another module, and a private field or property cannot be read or written to from another module. By placing related class declarations in the same module, you can give the classes access to one another's private members without making those members more widely accessible. For a member to be visible only inside its class, it needs to be declared strict private.

A protected member is visible anywhere in the module where its class is declared and from any descendent class, regardless of the module where the descendent class appears. A protected method can be called, and a protected field or property read or written to, from the definition of any method belonging to a class that descends from the one where the protected member is declared. Members that are intended for use only in the implementation of derived classes are usually protected.

A public member is visible wherever its class can be referenced.

Strict Visibility Specifiers

In addition to private and protected visibility specifiers, the Delphi compiler supports additional visibility settings with greater access constraints. These settings are strict private and strict protected visibility. These settings can be used in Win32 applications.

Class members with strict private visibility are accessible only within the class in which they are declared. They are not visible to procedures or functions declared within the same unit. Class members with strict protected visibility are visible within the class in which they are declared, and within any descendent class, regardless of where it is declared. Furthermore, when instance members (those declared without the class or class var keywords) are declared strict private or strict protected, they are inaccessible outside of the instance of a class in which they appear. An instance of a class cannot access strict protected or strict protected instance members in other instances of the same class.

Delphi's traditional private visibility specifier maps to the CLR's assembly visibility. Delphi's protected visibility specifier maps to the CLR's assembly or family visibility.

Note: The word strict is treated as a directive within the context of a class declaration. Within a class declaration you cannot declare a member named 'strict', but it is acceptable for use outside of a class declaration.

Your version of Delphi, Delphi 7, does not support the strict specifiers.



回答3:

Here are two sample units to show the visibility of private, protected and public parts from a class.

unit BaseClass;

interface

type
  TBaseClass0 = class
  strict private
    FStrictPrivate : Integer;
  private
    FPrivate : Integer;
  strict protected
    FStrictProtected : Integer;
  protected
    FProtected : Integer;
  public
    FPublic : Integer;

    procedure DoSomeThing; virtual;
  end;

  TBaseClass1 = class( TBaseClass0 )

  public
    procedure DoSomeThing; override;
  end;

procedure DoSomeThing( ABase : TBaseClass0 );

implementation

{ TBaseClass0 }

procedure TBaseClass0.DoSomeThing;
begin
  FStrictPrivate := 0;
  FPrivate := 0;
  FStrictProtected := 0;
  FProtected := 0;
  FPublic := 0;
end;

{ TBaseClass1 }

procedure TBaseClass1.DoSomeThing;
begin
  inherited;
  // FStrictPrivate := 1; // no access
  FPrivate := 1;
  FStrictProtected := 1;
  FProtected := 1;
  FPublic := 1;
end;

procedure DoSomeThing( ABase : TBaseClass0 );
begin
  with ABase do
    begin
      // FStrictPrivate := 3; // no access
      FPrivate := 3;
      // FStrictProtected := 3; // no access
      FProtected := 3;
      FPublic := 3;
    end;
end;

end.

unit BaseClass2;

interface

uses
  BaseClass;

type
  TBaseClass2 = class( TBaseClass0 )

  public
    procedure DoSomeThing; override;
  end;

procedure DoSomeThing( ABase : TBaseClass0 );

implementation

{ TBaseClass2 }

procedure TBaseClass2.DoSomeThing;
begin
  inherited;
  // FStrictPrivate := 2; // no access
  // FPrivate := 2; // no access
  FStrictProtected := 2;
  FProtected := 2;
  FPublic := 2;
end;

procedure DoSomeThing( ABase : TBaseClass0 );
begin
  with ABase do
    begin
      // FStrictPrivate := 4; // no access
      // FPrivate := 4; // no access
      // FStrictProtected := 4; // no access
      // FProtected := 4; // no access
      FPublic := 4;
    end;
end;

end.