Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen (https://www.delphipraxis.net/162996-klasse-von-tthread-ableiten-und-interface-implementieren-objekt-erstellen.html)

mika 12. Sep 2011 12:35

Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Hallo Forum,

lang ists her das ich hier mal was gepostet habe :) Da ich aber jetzt wieder vermehrt mit Delphi arbeite würde ich gerne mal eine Frage stellen.

Ich habe eine Klasse geschrieben, die abgeleitet von TThread ist und ein Interface implementiert, so als Beispiel:
Code:
type
  TMeineKlasse = Class(TThread, IInterfaceMein)
  end;

  TZweiteKlasse = Class(TInterfacedObjekt, IInterfaceZwei)
  end;
Bei TZweiteKlasse gelingt folgender aufruf, bei TMeineKlasse leider nicht, woran kann es liegen?
Code:
var
  meinInterface: IInterfaceMein;
  zweiInterface: IInterfaceZwei;
begin
  meinInterface := TMeineKlasse.Create AS IInterfaceMein; // Operator ist auf Operand nicht anwendbar
  zweiInterface := TZweiteKlasse AS IInterfaceZwei; // Geht
end;
Gibt es irgendwas einfaches das ich vergessen habe? Oder liegt es daran das eine Klasse von TTHread abgeleitet wurde?

Mfg, Mika

Uwe Raabe 12. Sep 2011 12:47

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Da das IInterfaceMein implizit von IInterface abgeleitet ist, gehören dazu natürlich auch Implementierungen der dort deklarierten Methoden - insbesondere QueryInterface! Da der Compiler schon viel eher meckern würde, wenn diese Methoden nicht in deiner TThread-Ableitung enthalten wären, denke ich daß du die auch tatsächlich implementiert hast.

Wenn du jetzt dem Compiler sagst, daß dein TThread-Abkömmling das IInterface tatsächlich implementiert, sollte es auch gehen:

Delphi-Quellcode:
TMeineKlasse = Class(TThread, IInterface, IInterfaceMein)

himitsu 12. Sep 2011 13:03

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Wenn du das IInterface selber einbindest, dann mußt du natürlich auch die Methoden dieses Interfaces selber implementieren,
aber dafür kannst'e dir auch einfach alles Nötige aus dem TInterfacedObject rauskopieren.

mika 12. Sep 2011 16:14

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Hei,

danke erstmal für die Antworten. Die Methoden des Interfaces habe ich eingebunden :) Hier mal zur besseren Verständnis richtiger Code:

Das Problem ist das gleiche, nur das man das AUgenmerk auf TDeviceController legt.

Interfaces
Code:
type
  { Forwardeklarationen }
  IDeviceController = interface;
  IDeviceEntity = interface;

  { Interface unserer obersten Controllerklasse }
  ILineController = interface(IInterface)['{4096970D-4269-4626-B710-AF753D80D0BF}']
    { Initialisiert den Controller mit den gegebenen Daten }
    function Initialize(db: TAdsConnection; id: Integer): Boolean;
    { Finalisiert den Controller, entfernt alle Daten }
    function Finalize: Boolean;

    { Setzt die Genauigkeit der Protokollierung }
    function SetLoglevel(ll: Integer): Boolean;

    { Gibt die Datenbankverbindung zurueck die angegeben wurde }
    function GetDatabaseConnection: TAdsConnection;
    function GetDatabaseConfigurationKey: Integer;

    { Setzt die Callbackmethode die der Controller aufrufen soll }
    function SetCallbackMethod(cm: TCallbackMethod): Boolean;

    { Verarbeitet einen DeviceStatus und reicht ihn an den Callback weiter }
    function ProcessDeviceStatus(ds: TDeviceStatus): Boolean;

    { Gibt die Anzahl der DeviceController zurück }
    function GetDeviceControllerCount: Integer;
    { Gibt den Index des übergebenen DeviceControllers wieder }
    function GetDeviceControllerIndex(dc: IDeviceController): Integer;
    { Gibt den DeviceController des übergebenen Index wieder }
    function GetDeviceControllerByIndex(index: Integer): IDeviceController;

    { Fügt einen neuen DeviceController hinzu }
    function AddDeviceController(dc: IDeviceController): Boolean;
    { Entfernt den übergebenen DeviceController }
    function RemoveAllDeviceController: Boolean;
    function RemoveDeviceController(index: Integer): Boolean; overload;
    function RemoveDeviceController(dc: IDeviceController): Boolean; overload;

    { Startet den übergebenen DeviceController }
    function StartAllDeviceController: Boolean;
    function StartDeviceController(index: Integer): Boolean; overload;
    function StartDeviceController(dc: IDeviceController): Boolean; overload;
    { Stoppt den übergebenen DeviceController }
    function StopAllDeviceController: Boolean;
    function StopDeviceController(index: Integer): Boolean; overload;
    function StopDeviceController(dc: IDeviceController): Boolean; overload;
    { Aktiviert den übergebenen DeviceController, somit wird er bei der
      Abfrage der DeviceController mit einbezogen }
    function ActivateAllDeviceController: Boolean;
    function ActivateDeviceController(index: Integer): Boolean; overload;
    function ActivateDeviceController(dc: IDeviceController): Boolean; overload;
    { Deaktiviert den übergebenen DeviceController, somit wird er bei der
      Abfrage der DeviceController übersprungen }
    function DeactivateAllDeviceController: Boolean;
    function DeactivateDeviceController(index: Integer): Boolean; overload;
    function DeactivateDeviceController(dc: IDeviceController): Boolean; overload;
  end;

  { Interface unserer Controllerklasse für die einzelnen Verbindungen/Module }
  IDeviceController = interface(IInterface)['{0217D970-51CC-49AD-944E-E9B0B86C6C14}']
    { Initialisiert den Controller mit den gegebenen Daten }
    function Initialize(lc: ILineController; id: Integer): Boolean;
    { Finalisiert den Controller, entfernt alle Daten }
    function Finalize: Boolean;
   
    { Setzt die Genauigkeit der Protokollierung }
    function SetLoglevel(ll: Integer): Boolean;

    { Setzt den LineController dieses Objekts, wichtig um Daten weiterzugeben }
    function SetLineController(lc: ILineController): Boolean;
    { Gibt den LineController dieses Objektszurück }
    function GetLineController: ILineController;

    { Setzt die Verbindung dieses Controllers, also Comport oder TCP/IP }
    function SetConnection(cnnct: IPort): Boolean;
    { Ermittelt die Verbindung dieses Controllers }
    function GetConnection: IPort;
    { Oeffnet die Verbindung }
    function OpenConnection(ps: TPortSettings): Boolean;
    { Schliesst die Verbindung }
    function CloseConnection: Boolean;
    { Liest von der Verbindung }
    function ReadConnection: String; overload;
    function ReadConnection(ByteCount: Integer): String; overload;
    { Schreibt auf die Verbindung }
    function WriteConnection(Text: String): Boolean;

    { Aktiviert den Controller, heisst er soll arbeiten falls gefragt }
    function Activate: Boolean;
    { Deaktiviert den Controller, Controller arbeitet nicht }
    function Deactivate: Boolean;

    { Startet die Abfrage der einzelnen Module die angeschlossen sind }
    function Start: Boolean;
    { Beendet die Abfrage der einzelnen Module die angeschlossen sind }
    function Stop: Boolean;

    { Gibt die Anzahl der angeschlossenen DeviceEntities zurück }
    function GetDeviceEntityCount: Integer;
    { Gibt den Index des übergebenen DeviceEntity wieder }
    function GetDeviceEntityIndex(de: IDeviceEntity): Integer;
    { Gibt das DeviceEntity des übergebenen Index wieder }
    function GetDeviceEntityByIndex(index: Integer): IDeviceEntity;

    { Fügt ein neues DeviceEntity hinzu }
    function AddDeviceEntity(de: IDeviceEntity): Boolean;
    { Entfernt das übergebene DeviceEntity }
    function RemoveAllDeviceEntitites: Boolean;
    function RemoveDeviceEntity(index: Integer): Boolean; overload;
    function RemoveDeviceEntity(de: IDeviceEntity): Boolean; overload;

    { Aktiviert das übergebenen DeviceEntity, somit wird es bei der
      Abfrage der DeviceEntities mit einbezogen }
    function ActivateAllDeviceEntities: Boolean;
    function ActivateDeviceEntity(index: Integer): Boolean; overload;
    function ActivateDeviceEntity(de: IDeviceEntity): Boolean; overload;
    { Dektiviert das übergebenen DeviceEntity, somit wird es bei der
      Abfrage der DeviceEntities ausgelassen }
    function DeactivateAllDeviceEntities: Boolean;
    function DeactivateDeviceEntity(index: Integer): Boolean; overload;
    function DeactivateDeviceEntity(de: IDeviceEntity): Boolean; overload;
  end;

  IDeviceEntity = interface(IInterface)['{E7803FED-19E9-462C-9289-2165E0464F53}']
    { Initialisiert den Controller mit den gegebenen Daten }
    function Initialize(lc: ILineController; dc: IDeviceController; id: Integer): Boolean;
    { Finalisiert den Controller, entfernt alle Daten }
    function Finalize: Boolean;

    { Setzt die Genauigkeit der Protokollierung }
    function SetLoglevel(ll: Integer): Boolean;

    { Setzt den LineController dieses Objekts, wichtig um Daten weiterzugeben }
    function SetLineController(lc: ILineController): Boolean;
    { Setzt den DeviceController dieses Objekts, wichtig um Daten weiterzugeben }
    function SetDeviceController(dc: IDeviceController): Boolean;
    { Gibt den LineController dieses Objekts wieder }
    function GetLineController: ILineController;
    { Gibt den DeviceController dieses Objekts wieder }
    function GetDeviceController: IDeviceController;

    { Aktiviert das modul, heisst er soll arbeiten falls gefragt }
    function Activate: Boolean;
    { Deaktiviert das Modul, Modul arbeitet nicht }
    function Deactivate: Boolean;

    { Liest den aktuellen Gerätestatus aus }
    function GetDeviceStatus: TDeviceStatus;
    { Setzt den aktuellen Gerätestatus. }
    function SetDeviceStatus(ds: TDeviceStatus): Boolean;

    { Setzt das Relais auf den angegebenen Status, falls vorhanden }
    function SetRelaisState(ns: Boolean): Boolean;

    { Schreibt den gegebenen Text auf das Display, falls vorhanden }
    function SetDisplayText(nt: String): Boolean;

    { Hat das Geraet die angegebene Eigenschaft? }
    function IsRfidModule: Boolean;
    function IsDisplayModule: Boolean;
    function IsRelaisModule: Boolean;
    function IsScannerModule: Boolean;
    function IsNumpadModule: Boolean;
  end;
TLineController
Code:
  TLineController = class (TInterfacedObject, ILineController)
  private
    // Logger dieser Klasse
    Logfile: TFCSLogging;
    // Die Verbindung zu unserer Datenbank
    DBConnection: TAdsConnection;
    // Die CallbackMethode die vom Aufrufer gesetzt werden kann
    CallbackMethod: TCallbackMethod;
    // Konfigurationsschluessel in der Datenbank
    ConfigurationKey: Integer;
    // Die Liste mit unseren DeviceControllern
    DeviceControllers: TInterfaceList;

    // Der Titel dieses LineControllers
    Titel: String;

    // Legt die zu dieser Konfiguration gehörenden Unterobjekte an
    function InitializeComponents: Boolean;
    // Erstellt einen Thread der die CallbackMethode ausfuehrt falls angegeben
    function ExecuteCallback(ds: TDeviceStatus): Boolean;
    // Speichert einen Gerätestatus in der Datenbank
    function PushDeviceStatusToDatabase(ds: TDeviceStatus): Boolean;

  public
    // Standardkonstruktor dieser Klasse
    constructor Create;
    // Standarddestruktor dieser Klasse
    destructor Destroy; reintroduce;

    // Aus dem Interface geerbte Methoden
    function Initialize(db: TAdsConnection; id: Integer): Boolean;
    function Finalize: Boolean;

    function SetLoglevel(ll: Integer): Boolean;

    function GetDatabaseConnection: TAdsConnection;
    function GetDatabaseConfigurationKey: Integer;

    function SetCallbackMethod(cm: TCallbackMethod): Boolean;

    function ProcessDeviceStatus(ds: TDeviceStatus): Boolean;

    function GetDeviceControllerCount: Integer;
    function GetDeviceControllerIndex(dc: IDeviceController): Integer;
    function GetDeviceControllerByIndex(index: Integer): IDeviceController;

    function AddDeviceController(dc: IDeviceController): Boolean;

    function RemoveAllDeviceController: Boolean;
    function RemoveDeviceController(index: Integer): Boolean; overload;
    function RemoveDeviceController(dc: IDeviceController): Boolean; overload;

    function StartAllDeviceController: Boolean;
    function StartDeviceController(index: Integer): Boolean; overload;
    function StartDeviceController(dc: IDeviceController): Boolean; overload;
   
    function StopAllDeviceController: Boolean;
    function StopDeviceController(index: Integer): Boolean; overload;
    function StopDeviceController(dc: IDeviceController): Boolean; overload;

    function ActivateAllDeviceController: Boolean;
    function ActivateDeviceController(index: Integer): Boolean; overload;
    function ActivateDeviceController(dc: IDeviceController): Boolean; overload;

    function DeactivateAllDeviceController: Boolean;
    function DeactivateDeviceController(index: Integer): Boolean; overload;
    function DeactivateDeviceController(dc: IDeviceController): Boolean; overload;
  end;
TDeviceController
Code:
type
  TDeviceController = class (TThread, IDeviceController)
  private
    // Referenzzaehler dieses InterfacedObjekts
    FRefCount: Integer;
    // Logger dieser Klasse
    Logfile: TFCSLogging;
    // Konfigurationsschluessel in der Datenbank
    ConfigurationKey: Integer;
    // LineController dem dieser DeviceController untergeordnet ist
    LineController: ILineController;
    // Verbindung die dieser DeviceController bereitstellt
    Port: IPort;
    // Die Liste mit unseren DeviceEntities
    DeviceEntities: TInterfaceList;

    // Der Titel dieses LineControllers
    Titel: String;
    // Ist der Controller aktiv? Sollen Geräte abgefragt werden?
    Aktiv: Boolean;
    // Zeit in Millisekunden zwischen zwei Abfragen
    DelayMSecs: Integer;

    // Methoden die Klassen benoetigen die ein Interface implementieren
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

    // Legt die zu dieser Konfiguration gehörenden Unterobjekte an
    function InitializeComponents: Boolean;

  protected
    procedure Execute; override;

  public
    property RefCount: Integer read FRefCount;
    // Standardkonstruktor dieser Klasse
    constructor Create; reintroduce;
    // Standarddestruktor dieser Klasse
    destructor Destroy; reintroduce;

    // Aus dem Interface geerbte Methoden
    function Initialize(lc: ILineController; id: Integer): Boolean;
    function Finalize: Boolean;

    function SetLoglevel(ll: Integer): Boolean;

    function SetLineController(lc: ILineController): Boolean;
    function GetLineController: ILineController;

    function SetConnection(cnnct: IPort): Boolean;
    function GetConnection: IPort;

    function OpenConnection(ps: TPortSettings): Boolean;
    function CloseConnection: Boolean;
    function ReadConnection: String; overload;
    function ReadConnection(ByteCount: Integer): String; overload;
    function WriteConnection(Text: String): Boolean;

    function Activate: Boolean;
    function Deactivate: Boolean;

    function Start: Boolean;
    function Stop: Boolean;

    function GetDeviceEntityCount: Integer;
    function GetDeviceEntityIndex(de: IDeviceEntity): Integer;
    function GetDeviceEntityByIndex(index: Integer): IDeviceEntity;

    function AddDeviceEntity(de: IDeviceEntity): Boolean;

    function RemoveAllDeviceEntitites: Boolean;
    function RemoveDeviceEntity(index: Integer): Boolean; overload;
    function RemoveDeviceEntity(de: IDeviceEntity): Boolean; overload;

    function ActivateAllDeviceEntities: Boolean;
    function ActivateDeviceEntity(index: Integer): Boolean; overload;
    function ActivateDeviceEntity(de: IDeviceEntity): Boolean; overload;

    function DeactivateAllDeviceEntities: Boolean;
    function DeactivateDeviceEntity(index: Integer): Boolean; overload;
    function DeactivateDeviceEntity(de: IDeviceEntity): Boolean; overload;
  end;
TDeviceEntity, IPort und so weiter sollten in dem Kontext keine Rolle spielen denk ich mal...
JKetzt möchte ich halt in einer Methode von TLineController folgendes machen können:

Code:
var
  meinDevice: IDeviceController;
begin
  meinDevice := TDeviceController.Create AS IDeviceController;
end;
aber das geht wie gesagt nicht und ich könnte mir das nur erklären weil DeviceController halt von TThread abgeleitet ist.

Uwe Raabe 12. Sep 2011 16:21

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Ich wiederhole:

type
TDeviceController = class (TThread, IInterface, IDeviceController)

mika 12. Sep 2011 23:07

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Danke für den Tipp Herr Raabe, ich werd das morgen mal ausprobieren.

Ich hab gedacht da IDeviceController schon IInterface implementiert, hat TDeviceController das dadurch auch. Ich war mir nicht sicher ob das bei den Interfaces in Delphi mitvererbt wird.

Deswegen hatte ich auch folgende Zeilen in TDeviceController aufgenommen.
Code:
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

Schönen Abend noch.

Sir Rufo 12. Sep 2011 23:21

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Zitat:

Zitat von mika (Beitrag 1123885)
Ich hab gedacht da IDeviceController schon IInterface implementiert, hat TDeviceController das dadurch auch. Ich war mir nicht sicher ob das bei den Interfaces in Delphi mitvererbt wird.

deswegen sollte man sich auch die Doku mal anschauen ;)

Schau mal wie
Delphi-Quellcode:
TInterfacedObject
deklariert wird.

sx2008 13. Sep 2011 03:40

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Ich glaube, du mutest deiner Thread-Klasse zuviel zu.
Anstatt das Interface IDeviceController zu implementieren würde es doch ausreichen,
wenn die Threadklasse von Aussen eine Instanz von IDeviceController zugewiesen bekommt.

Hier mal stark vereinfacht die Unterschiede:
Delphi-Quellcode:
// dein Vorschlag
TDeviceController = class(TThread, IDeviceController)

private
  // hier müssen alle Methoden von IDeviceController implementiert werden
  ...
public
  procedure Execute;override;

end;
// ======================================================================
// mein Vorschlag
TDeviceThread = class(TThread)

public
  // "DeviceController" muss von Aussen übergeben werden und danach
  // der Thread mit Resume() gestartet werden
  DeviceController : IDeviceController;
  procedure Execute;override; // benützt "DeviceController"
end;
Mein Vorschlag hat den Vorteil, dass er einfacher umzusetzen ist und ausserdem wird das Interface IDeviceController von einer eigenen Klasse implementiert.
Diese bedeutet, dass dein Code zunächst auch ohne Multithreading testbar ist.
Erst später kommt eine (oder mehrere!) Threadklasse hinzu, der schon bestehenden Code im Kontext eines Threads ausführt.

Uwe Raabe 13. Sep 2011 07:15

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Zitat:

Zitat von mika (Beitrag 1123885)
Ich hab gedacht da IDeviceController schon IInterface implementiert, hat TDeviceController das dadurch auch. Ich war mir nicht sicher ob das bei den Interfaces in Delphi mitvererbt wird.

IDeviceController erbt zwar die Methoden von IInterface und somit muss jede Instanz, die IDeviceController unterstützt (Supports), auch diese Methoden implementieren, aber jede Klasse unterstützt genau die Interfaces, die hinter der Parent-Klasse angegeben sind:

Delphi-Quellcode:
TMyClass = class(TObject, IDeviceController)
unterstützt IDeviceController aber nicht IInterface,

Delphi-Quellcode:
TMyClass = class(TObject, IInterface, IDeviceController)
unterstützt IInterface und IDeviceController.

Natürlich wird Interface-Unterstützungg vererbt. Deswegen funktioniert auch
Delphi-Quellcode:
TMyClass = class(TInterfacedObject, IDeviceController)
.

Das erste mag etwas verwundern, wenn man Interface-Vererbung (die ähnlich wie Klassenvererbung funktioniert) und Interface-Unterstützung (das was man mit Supports bzw. QueryInterface abfragt) nicht auseinanderhält. Es handelt sich aber hierbei um zwei verschiedene Dinge.

mika 13. Sep 2011 07:42

AW: Klasse von TTHread ableiten und Interface implementieren, Objekt erstellen
 
Okai, das hat funktioniert. Danke euch für eure Hilfe!


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:52 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz