Einzelnen Beitrag anzeigen

Benutzerbild von chaosben
chaosben

Registriert seit: 27. Apr 2005
Ort: Görlitz
1.358 Beiträge
 
Delphi XE2 Professional
 
#2

Re: Verständnisfrage zur Benutzung von Interfaces

  Alt 24. Jul 2009, 06:12
Es gibt im Zusammenhang mit Interfaces eine wichtige Grundregel:
Arbeite niemals mit dem Objekt und den Interfacen gleichzeitig!
(Wenn man genau weiß was man tut, kann man das trotzdem machen, aber es ist nicht empfehlenswert)

Ich hab dir im folgenden dein Beispiel mal umgebaut. Um es nicht zu kompliziert zu machen, wird der Wert jetzt im Konstruktor übergeben und ISquare kann seine Zahl als String zurückgeben.

Delphi-Quellcode:
type
  ISquare = interface(IInterface)
    ['{4F30FDE5-9C8C-4F34-A828-FA32B1C0DA3F}']
    procedure Square;
    function NumberAsString : String;
  end;

  TInt = class(TInterfacedObject, ISquare)
  private
    FInt: Integer;
  public
    constructor Create(ANumber : Integer);
    procedure Square;
    property Number: Integer read FInt write FInt;
    function NumberAsString : String;
  end;

  TFloat = class(TInterfacedObject, ISquare)
  private
    FFloat: Single;
  public
    constructor Create(ANumber : Single);
    procedure Square;
    property Number: Single read FFloat write FFloat;
    function NumberAsString : String;
  end;


  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TInt.Create(ANumber: Integer);
begin
  FInt := ANumber;
end;

function TInt.NumberAsString: String;
begin
  Result := IntToStr(FInt);
end;

procedure TInt.Square;
begin
  FInt:= FInt * FInt;
end;

constructor TFloat.Create(ANumber: Single);
begin
  FFloat := ANumber;
end;

function TFloat.NumberAsString: String;
begin
  Result := FloatToStr(FFloat)
end;

procedure TFloat.Square;
begin
  FFloat:= FFloat * FFloat;
end;

procedure SquareIt(aNumber: ISquare); //Fehler ohne const, mit kein Fehler
begin
  aNumber.Square;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  aInt,
  aFloat: ISquare;
  //MyInterface: ISquare; unnötig
begin
  aInt:= TInt.Create(5);
  //MyInterface:= aInt; //Interface Referenz Counter geht hoch
  aFloat:= TFloat.Create(5);
  //aInt.Number:= 5; gibts nicht mehr
  //MyInterface.Square;
  //MyInterface:= nil; //Zähler geht wieder runter
  //aFloat.Number:= 5; gibts nicht mehr
  aInt.Square;
  aFloat.Square;
  ShowMessage(aInt.NumberAsString);
  ShowMessage(aFloat.NumberAsString);
  //SquareIt(aInt); //während der Aufrufe geht der Zähler auch hoch
  //SquareIt(Float);
  //ShowMessage(IntToStr(aInt.Number));
  //ShowMessage(FloatToStr(aFloat.Number));
  //aInt.Free;
  //aFloat.Free;
end;
Das Problem in deiner Implementation war, das das Objekt freigegeben wurde, nachdem es einmal als Interface benutzt wurde. Das kommt daher das es nach dem erstellen(.Create) den RefCount 0 hat. Durch die Zuweisung an ein Interface oder die Übergabe in eine Funktion als Interface wird der RefCount auf 1 gesetzt. Am Ende der Prozedur oder durch eine Neubelegung der interfacevariable sinkt der RefCount auf 0 und für das Objekt wird .Free aufgerufen. Jede nachfolgende Verwendung wirft dann eine AV.
Benjamin Schwarze
If I have seen further it is by standing on the shoulders of Giants. (Isaac Newton)
  Mit Zitat antworten Zitat