Autor Beitrag
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 10.03.11 12:43 
Hallo Freunde,

ich sehe den Wald vor Bäumen nicht mehr, fürchte ich :? Naja, nach all den Jahren (begonnen mit Turbo Pascal 6.0 in OOP zu denken) kann sowas mal vorkommen. Mein Problem ist, das man offensichtlich Members gleichen Namens nicht korrekt ansprechen kann. Folgender Code (Delphi 7) mag verdeutlichen, was ich meine:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
  TUsedClass1 = class(TObject)
  private
    FInternalValue: string;
    function GetInternalValue: string;
  protected
  public
    constructor Create;
    property InternalValue: string read GetInternalValue;
  end;

  TUsedClass2 = class(TObject)
  private
    FInternalValue: string;
    function GetInternalValue: string;
  protected
  public
    constructor Create;
    property InternalValue: string read GetInternalValue;
  end;


Zwei simple Klassen, die sich nur im Konstruktor unterscheiden:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
constructor TUsedClass1.Create;
begin
     self.FInternalValue:='Hallo 1';
end;

function TUsedClass1.GetInternalValue: string;
begin
     result:=self.FInternalValue;
end;

constructor TUsedClass2.Create;
begin
     self.FInternalValue:='Hallo 2';
end;

function TUsedClass2.GetInternalValue: string;
begin
     Result:=self.FInternalValue;
end;


So. Nun basteln wir uns ne Klasse, die TUsedClass1 als Member beinhaltet:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
  TAnyClass1 = class(TObject)
  public
    Fx: TUsedClass1;
    constructor Create;
    function GetFxValue: stringvirtual;
  end;

constructor TAnyClass1.Create;
begin
     self.Fx:=TUsedClass1.Create;
end;

function TAnyClass1.GetFxValue: string;
begin
     Result:=self.Fx.InternalValue;
end;


Von dieser Klasse leiten wir eine weitere Klasse ab. Das besondere ist das Feld "Fx", das nun nicht mehr vom Typ TUsedClass1 ist, sondern vom Typ TUsedClass2:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
  TAnyClass2 = class(TAnyClass1)
  public
    Fx: TUsedClass2; //Gleicher Name, anderer Typ !
    constructor Create;
    function GetFxValue: stringoverride;
  end;

constructor TAnyClass2.Create;
begin
     self.Fx:=TUsedClass2.Create;
end;

function TAnyClass2.GetFxValue: string;
begin
     Result:=inherited GetFxValue;
end;


So weit, so simpel. Instanziere ich nun ein TAnyClass2 und rufe GetFxValue auf, wird korrekt in TAnyClass2.GetFxValue gesprungen, dann zu TAnyClass1.GetFxValue. Alles logisch. Der Zugriff in GetFxValue erfolgt aber auf ein Feld "Fx" vom Typ TUsedClass1 - das nicht existiert und folglich eine Exception geworfen wird.

Ich habe so ziemlich alles probiert, was mir eingefallen ist, und die einzige Lösung ist, kurzerhand den Code von TAnyClass1.GetFxValue 1:1 zu duplizieren. Aber dann brauche ich keine Verebung mehr.

Wie dicht ist der Wald, in dem ich stehe ? Oder ist das, was ich da vorhabe, gar nicht vorgesehen ?

Danke fürs helfen,

Olaf

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 10.03.11 13:23 
hier fehlte inherited
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
constructor TAnyClass2.Create;
begin
     inherited;
     self.Fx:=TUsedClass2.Create;
end;


das was Du vermutlich vorhast wäre über eine gemeinsame Basisklasse für für TUsedClass1/TUsedClass2 mit einem virtuellen GetInternalValue zu lösen.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
OlafSt Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 10.03.11 13:34 
user profile iconbummi hat folgendes geschrieben Zum zitierten Posting springen:

das was Du vermutlich vorhast wäre über eine gemeinsame Basisklasse für für TUsedClass1/TUsedClass2 mit einem virtuellen GetInternalValue zu lösen.


Ups, das mit dem inherited ist logisch. Daher auch der Absturz.

Das mit der gemeinsamen Basisklasse für TUsedClass habe ich schon versucht. Ohne das fehlende Inherited krachts, mit dem Inherited bekomme ich 2x ein ShowMessage mit "Hallo 1". Es wird also weiterhin auf das Fx mit dem Typ TUsedClass1 zugegriffen.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
  TUsedClass = Class(TObject)
  private
    FInternalValue: string;
    function GetInternalValue: stringvirtual;
  protected
  public
    property InternalValue: string read GetInternalValue;
  end;

  TUsedClass1 = class(TUsedClass)
  private
  protected
  public
    constructor Create;
  end;

  TUsedClass2 = class(TUsedClass)
  private
  protected
  public
    constructor Create;
  end;


Natürlich kann ich GetInternalValue jedesmal überschreiben - aber dann habe ich ja 3x denselben Code und genau das soll die Vererbung ja vermeiden. Ich habe auch schon das property weggenommen und den Getter in den public-Bereich verschoben. Same Result.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 10.03.11 14:05 
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
unit Unit1;

interface

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

type
 TUsedClassBase = class(TObject)
  private
    FInternalValue: string;
    function GetInternalValue: string;virtual;
  protected
  public
    constructor Create;
    property InternalValue: string read GetInternalValue;
  end;

 TUsedClass1 = class(TUsedClassBase)
  private
    FInternalValue: string;
    function GetInternalValue: string;override;
  protected
  public
    constructor Create;
    property InternalValue: string read GetInternalValue;
  end;

  TUsedClass2 = class(TUsedClassBase)
  private
    FInternalValue: string;
    function GetInternalValue: string;override;
  protected
  public
    constructor Create;
    property InternalValue: string read GetInternalValue;
  end;
  TAnyClass1 = class(TObject)
  public
    Fx: TUsedClass1;
    constructor Create;
    function GetFxValue: stringvirtual;
  end;


  TAnyClass2 = class(TAnyClass1)
  public
    Fx: TUsedClass2; //Gleicher Name, anderer Typ !
    constructor Create;
    function GetFxValue: stringoverride;
  end;




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

var
  Form1: TForm1;

implementation

{$R *.dfm}
constructor TUsedClass1.Create;
begin
     self.FInternalValue:='Hallo 1';
end;

function TUsedClass1.GetInternalValue: string;
begin
     result:=self.FInternalValue;
end;

constructor TUsedClass2.Create;
begin
     self.FInternalValue:='Hallo 2';
end;

function TUsedClass2.GetInternalValue: string;
begin
     Result:=self.FInternalValue;
end;

constructor TAnyClass1.Create;
begin
     self.Fx:=TUsedClass1.Create;
end;

function TAnyClass1.GetFxValue: string;
begin
     Result:=FX.GetInternalValue;
end;


constructor TAnyClass2.Create;
begin
     inherited;
     self.Fx:=TUsedClass2.Create;
end;

function TAnyClass2.GetFxValue: string;
begin
     Result:= FX.GetInternalValue;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  With  TAnyClass1.Create do
    begin
    Showmessage('TAnyClass1 ' + GetFxValue);
    Free;
    end;
  With  TAnyClass2.Create do
    begin
    Showmessage('TAnyClass2 ' + GetFxValue);
    Free;
    end;
end;

{ TUsedClassBase }

constructor TUsedClassBase.Create;
begin
 inherited;
end;

function TUsedClassBase.GetInternalValue: string;
begin
   Result := '';
end;

end.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
OlafSt Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 10.03.11 14:17 
Hui, danke !

Allerdings: TUsedClass1.GetInternalValue wird in TUsedClass2 1:1 dupliziert. Desgleichen in TAnyClass1.GetFxValue und TAnyClass2.GetFxValue, die 1:1 dupliziert sind.

Wenn wir uns von meinem Beispiel lösen und in mein real existierendes Problem springen, muß ich nun 15 Routinen mit ein paar hundert Zeilen Code 1:1 duplizieren, denn sie machen beides identisch, nur auf einer anderen Membervariablen. Ist also pures Copy & Paste.

Ist das wirklich so beabsichtigt ? Ehrlich gesagt sehe ich plötzlich nicht mehr den Sinn hinter der Vererbung - außer das ich immer denselben Prozedurnamen habe. Das kanns doch nicht sein :cry:

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 10.03.11 14:39 
brauchst Du ja nicht, ich hatte neben dem Arbeiten schnell was in Deinen Code reingeflickt, so wie unten geht es auch, gegf. kannst Du noch mehr optimieren, bin gerade etwas im Stress...
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
unit Unit1;

interface

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

type
 TUsedClassBase = class(TObject)
  private
    FInternalValue: string;
    function GetInternalValue: string;virtual;
  protected
  public
    constructor Create;
    property InternalValue: string read GetInternalValue;
  end;

 TUsedClass1 = class(TUsedClassBase)
  private
    FInternalValue: string;
  protected
  public
    constructor Create;
  end;

  TUsedClass2 = class(TUsedClassBase)
  private
    FInternalValue: string;
  protected
  public
    constructor Create;
  end;

  TAnyClass1 = class(TObject)
  public
    Fx: TUsedClass1;
    constructor Create;
    function GetFxValue: stringvirtual;
  end;


  TAnyClass2 = class(TAnyClass1)
  public
    Fx: TUsedClass2; //Gleicher Name, anderer Typ !
    constructor Create;
    function GetFxValue: stringoverride;
  end;




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

var
  Form1: TForm1;

implementation

{$R *.dfm}
constructor TUsedClass1.Create;
begin
     FInternalValue:='Hallo 1';
end;


constructor TUsedClass2.Create;
begin
     FInternalValue:='Hallo 2';
end;


constructor TAnyClass1.Create;
begin
     Fx:=TUsedClass1.Create;
end;

function TAnyClass1.GetFxValue: string;
begin
     Result:=FX.GetInternalValue;
end;


constructor TAnyClass2.Create;
begin
     inherited;
     Fx:=TUsedClass2.Create;
end;

function TAnyClass2.GetFxValue: string;
begin
     Result:= FX.GetInternalValue;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  With  TAnyClass1.Create do
    begin
    Showmessage('TAnyClass1 ' + GetFxValue);
    Free;
    end;
  With  TAnyClass2.Create do
    begin
    Showmessage('TAnyClass2 ' + GetFxValue);
    Free;
    end;
end;

{ TUsedClassBase }

constructor TUsedClassBase.Create;
begin
 inherited;
end;

function TUsedClassBase.GetInternalValue: string;
begin
   Result := '';
end;

end.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
OlafSt Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 10.03.11 15:13 
Okay, das habe ich mal probiert. Beide Aufrufe
ausblenden Delphi-Quelltext
1:
    Showmessage('TAnyClass1 ' + GetFxValue);					


landen bei TUsedBaseClass.GetInternalValue. Ergo ist die Ausgabe "TAnyClass1 " und "TAnyClass2 " in den ShowMessages. Erstaunlicherweise zeigt der Debugger, sobald man in den Routinen "GetFxValue" die Maus auf "FX." hovern läßt, korrekt den Inhalt von FInternalValue an.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 10.03.11 18:18 
ich hatte ja geschrieben daß ich gerade im Druck bin....
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
unit Unit1;

interface

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

type
 TUsedClassBase = class(TObject)
  private
    FInternalValue: string;
  protected
  public
    constructor Create;
    property InternalValue: string read FInternalValue;
  end;

 TUsedClass1 = class(TUsedClassBase)
  protected
  public
    constructor Create;
  end;
  TUsedClass2 = class(TUsedClassBase)
  protected
  public
    constructor Create;
  end;

  TAnyClass1 = class(TObject)
  public
    Fx: TUsedClass1;
    constructor Create;
    function GetFxValue: stringvirtual;
  end;


  TAnyClass2 = class(TAnyClass1)
  public
    Fx: TUsedClass2; //Gleicher Name, anderer Typ !
    constructor Create;
    function GetFxValue: stringoverride;
  end;




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

var
  Form1: TForm1;

implementation

{$R *.dfm}
constructor TUsedClass1.Create;
begin
     FInternalValue:='Hallo 1';
end;


constructor TUsedClass2.Create;
begin
     FInternalValue:='Hallo 2';
end;


constructor TAnyClass1.Create;
begin
     Fx:=TUsedClass1.Create;
end;

function TAnyClass1.GetFxValue: string;
begin
     Result:=FX.InternalValue;
end;


constructor TAnyClass2.Create;
begin
     inherited;
     Fx:=TUsedClass2.Create;
end;

function TAnyClass2.GetFxValue: string;
begin
     Result:= FX.InternalValue;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  With  TAnyClass1.Create do
    begin
    Showmessage('TAnyClass1 ' + GetFxValue);
    Free;
    end;
  With  TAnyClass2.Create do
    begin
    Showmessage('TAnyClass2 ' + GetFxValue);
    Free;
    end;
end;

{ TUsedClassBase }

constructor TUsedClassBase.Create;
begin
 inherited;
end;


end.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
OlafSt Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 10.03.11 19:18 
Gut, das ganze funktioniert - entspricht aber auch genau dem, was ich hier als "merkwürdig" angesprochen habe.

Nehmen wir also an, in TUsedClass1 finden wir jede Menge Programmcode und Hilfsroutinen, um mit einer ISDN-Karte Daten zu übertragen und auch ein Telefongespräch zu führen.

Nehmen wir weiter an, in TAnyClass1 finden wir jetzt ein Member namens "isdn", vom Typ TUsedClass1. Und eine Methode, die so aussieht (ich poste das Monster mit Absicht, damit deutlich wird, was das Problem ist):

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
procedure TAnyClass1.ActivateOutput(const Output: integer; const IsDuplex: boolean);
begin
     if IsDuplex then
         frmMain.log.WriteToLog('>> Activate Outputs for Duplex',nil,1)
     else
          frmMain.log.WriteToLog('>> Activate Outputs for Simplex',nil,1);
     case Output of
          0begin
                  frmMain.log.WriteToLog('>> Activate Output CC',nil,1);
                  //Hier haben wir z.B. unser isdn-Member im Einsatz
                  isdn.SendOutput(1-1,self.CC_Sound,self.CC_SubChannel-1);
                  FCCUsed:=true;
             end;
          1begin
                  if (FMon1ChannelUsed) and (FMon2ChannelUsed) then
                  begin
                       frmMain.log.WriteToLog('>> Activate Output MON1: No channel available',nil,1);
                       exit;
                  end;
                  if IsDuplex then
                  begin
                       if (FMon2ChannelUsed) or (FMon1ChannelUsed) then
                       begin
                            frmMain.log.WriteToLog('>> Activate Output MON1 (Duplex): Not enough channels available',nil,1);
                            exit;
                       end;

                       frmMain.log.WriteToLog('>> Activate Output MON1',nil,1);
                       isdn.SendOutput(5-1,self.Mon1_Sound,self.Mon1_SubChannel-1);
                       frmMain.log.WriteToLog('>> Activate Output MON2',nil,1);
                       isdn.SendOutput(6-1,self.Mon2_Sound,self.Mon2_SubChannel-1);
                       FMon1ChannelUsed:=true;
                       FMon2ChannelUsed:=true;
                       FIsDuplex:=true;
                  end
                  else
                  begin
                       if not FMon1Channelused then
                       begin
                            frmMain.log.WriteToLog('>> Activate Output MON1',nil,1);
                            isdn.SendOutput(5-1,self.Mon1_Sound,self.Mon1_SubChannel-1);
                            FMon1ChannelUsed:=true;
                            FIsDuplex:=false;
                       end;
                  end;
             end;
          2begin
                  if (FMon1ChannelUsed) and (FMon2ChannelUsed) then
                  begin
                       frmMain.log.WriteToLog('>> Activate Output MON2: Not enough channels available',nil,1);
                       exit;
                  end;
                  if ((FMon1ChannelUsed) or (FMon2ChannelUsed)) and (IsDuplex) then
                  begin
                       frmMain.log.WriteToLog('>> Activate Output MON2 (Duplex): Not enough channels available',nil,1);
                       exit;
                  end;

                  if IsDuplex then
                  begin
                       frmMain.log.WriteToLog('>> Activate Output MON1',nil,1);
                       isdn.SendOutput(5-1,self.Mon2_Sound,self.Mon2_SubChannel-1);
                       FMon1ChannelUsed:=true;
                       FIsDuplex:=true;
                  end
                  else
                      FIsDuplex:=false;
                  frmMain.log.WriteToLog('>> Activate Output MON2',nil,1);
                  isdn.SendOutput(6-1,self.Mon2_Sound,self.Mon2_SubChannel-1);
                  FMon2ChannelUsed:=true;
             end;
     end;
end;


Bitte nicht über den Code aufregen, er stammt nicht von mir.

Nun habe ich TUsedClass2 erstellt, das sich nach außen hin exakt so verhält, wie TUsedClass1, nur das ich nicht via ISDN kommuniziere, sondern via UDP. Ergo habe ich auch eine neue AnyClass gebaut, nämlich TAnyClass2. Natürlich enthält TAnyClass2 auch wieder ein Member namens "isdn", aber diesmal vom Typ TUsedClass2.

Um die OOP voll zu nutzen, habe ich nun eine Instanz namens TAC, vom Typ TAnyClass1. Je nachdem, ob ich via ISDN oder UDP telefonieren will, ändere ich meine Instanzierung ab:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
   TAC: TAnyClass1;

if UseISDN then
   TAC:=TAnyClass1.Create
else
   TAC:=TAnyClass2.Create;


Ist UseISDN=false, will ich also UDP nutzen, TAC ist also nun eine Instanz von TAnyClass2. Bei dem Versuch, TAC.ActivateOutput aufzurufen, lande ich aber unweigerlich in TAnyClass1.ActivateOutput. Dort wird das Member "isdn" angesprochen, das aber gar nicht existiert (und auch nicht darf, schließlich gibts kein ISDN).

Die einzige LÖsung scheint zu sein, TAnyClass1.ActivateOutput zu kopieren (sie also virtuell zu machen und in TAnyClass2 per override zu überschreiben). Daraus folgt: Die oben angegebene Methode habe ich nun zweimal als exakte Kopie im Programmcode. Und das nur, damit das richtige Member namens "isdn" angesprochen wird.

Ist es in OOP nicht so, das man eben solche Duplikate durch Vererbung vermeiden können soll ? Und wenn das so ist: Was mache ich dann falsch ? Das ist der Wald, den ich im Moment nicht sehe...

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 10.03.11 23:36 
vielleicht habe ich einen Hänger aber IMHO sollte es eine Basisklasse geben die alle Gemeinsamkeiten als Virtuals enthält, bei identischer Teil(Implementierung) bereits mit Code, die Implementierung für beide Kommunikationsvarianten kann nur in den Overrides der Ableitungen implementiert werden.
Ich würde also UDP nicht von ISDN ableiten sondern beide Klassen von einer gemeinsamen Basisklasse.
Aber vielleicht haben wir auch gerade einen Kommunikationsknoten....

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
OlafSt Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Fr 11.03.11 10:47 
Guten Morgen, Freunde !

Heute früh habe ich mich diesem Problem wieder zugewandt. Ersteinmal Danke für die Mühe, mir bei diesem Problem zu helfen. Ich weiß das zu schätzen, haben wir doch alle in der Woche genug zu tun :wink:

Die Idee, sowohl ISDN als auch UDP von einer gemeinsamen Basisklasse abzuleiten, habe ich aufgegriffen und in meinem Mini-Beispiel versucht. Also gibt es nun eine TAnyClassBase, von der sowohl TAnyClass1 als auch TAnyClass2 abgeleitet werden. Ergebnis: The same.

Dann habe ich versucht TAnyClass2 von TAnyClass1 abzuleiten. Ergebnis: The same.

Ich habs mit nem Typecast versucht, falls der Compiler irgendwas verbaselt ((TA as TAnyClass1).GetFxValue). Ergebnis: The same.

Ich habe den Compiler gewechselt (D7 -> D2006). Ergebnis: The same.

Offenbar ist das, was ich da vorhabe, überhaupt nicht vorgesehen. Dann aber frage ich mich ernsthaft, wie alle meine Programme bisher funktionieren können (von der VCL mal ganz zu schweigen, ich sage nur Tag-Property in allen von TComponent abstammenden Klassen).

Ich bin für weitere Ideen immer zu haben.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.