Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Probleme beim erstellen von VarArrays in Klasse


GR-Thunderstorm - Di 01.11.11 11:32
Titel: Probleme beim erstellen von VarArrays in Klasse
Hey!
Ich habe mich nach vielen Jahren Delphi-Abstinenz nun doch wieder mit meinem Delphi7 Enterprise auseinander gesetzt und möchte ein kleines Programm schreiben.
Damit es auch übersichtlich bleibt, möchte ich einige Functions / Procedures in eine andere Unit auslagern.


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:
unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Math, ExtCtrls, Buttons, ComCtrls, Mask, StrUtils;

type
  TForm1 = class(TForm)
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Functions;

{$R *.dfm}

procedure TForm1.Button2Click(Sender: TObject);
var Float: Real;
begin
  Float:=Bessel_1(2.405,100);
  ShowMessage(FloatToStr(Float));
end;

end.



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:
unit Functions;

interface
  uses Graphics, SysUtils, Math, MainUnit;

implementation


//uses MainUnit;

function Factorial_2(Int: Integer) : Extended;
begin
  if (Int <2then Result := 1
  else Result := Int*Factorial_2(Int-2);
end;

function Bessel_1(X: Extended; Steps: Integer) : Extended;
var i: Integer;
    PreResult: Real;
begin
  PreResult:=0;
  for i:=1 to Steps do
  begin
    PreResult:= PreResult + Power(-1, i+1 mod 2)*Power(X,i*2-1) / (Power(Factorial_2((i*2)-2),2)*i*2);
  end;

  Result:=PreResult;

end;

end.


Wenn ich das Programm starten will, springt er in der MainUnit an die Stelle, wo Bessel_1 aufgerufen werden soll und meckert: 'Undeclared identifier: Bessel_1'

Was mache ich denn falsch? :(



EDIT: Problemstellung hat sich geändert. :) Siehe weiter unten.


jaenicke - Di 01.11.11 11:47

Delphi weiß nicht, dass die Funktion für andere Units sichtbar sein soll.

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:
unit Functions;

interface

uses
  Graphics, SysUtils, Math, MainUnit;

function Factorial_2(Int: Integer): Extended;
function Bessel_1(X: Extended; Steps: Integer): Extended;


implementation

function Factorial_2(Int: Integer): Extended;
begin
  if (Int < 2then
    Result := 1
  else
    Result := Int * Factorial_2(Int - 2);
end;

function Bessel_1(X: Extended; Steps: Integer): Extended;
var
  i: Integer;
  PreResult: Real;
begin
  PreResult := 0;
  for i := 1 to Steps do
  begin
    PreResult := PreResult + Power(-1, i + 1 mod 2) * Power(X, i * 2 - 1) / (Power(Factorial_2((i * 2) - 2), 2) * i * 2);
  end;

  Result := PreResult;
end;

end.
Nebenbei: Unterstriche in Funktionsnamen sind kein guter Stil. ;-)


GR-Thunderstorm - Di 01.11.11 21:41

Danke, das hat funktioniert! :zustimm:
Geht es auch irgendwie, dass ich alle globalen Variablen in eine externe Unit auslagere?


jaenicke - Di 01.11.11 21:49

Verwende möglichst niemals globale Variablen. Das ist sehr schlechter Stil, da es die Übersicht enorm verringert...

Du kannst stattdessen z.B. Sachen in Klassen kapseln, je nachdem was du machst.


GR-Thunderstorm - Mo 07.11.11 21:37

Soweit so gut, ich wollte eine eigene Klasse erstellen, um in dieser einige Werte berechnen zu lassen.

Hier zunächst der Code:


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:
//VarsTypes.pas

type Mue = class
private
  Precision: Integer;
  Z0: Variant;
  ffg: Variant;
  MueIm: Variant;
  MueRe: Variant;

  procedure Assign_ffg(f: Variant);
  procedure Assign_Z(Z: Variant);

public
  procedure Create();

  property Z: Variant read Z0 write Assign_Z;
  property f_fg: Variant read ffg write Assign_ffg;
  property Im: Variant read MueIm;
  property Re: Variant read MueRe;
end;

implementation

uses Functions;

procedure TSensor.LO(Z:Integer);
begin
  Lift:=Z;
end;

procedure Mue.Create();
begin
  Precision:=160;
  self.Z0:=VarArrayCreate([0,0],VarVariant); //Debugger bleibt hier stehen mit Fehlermeldung
  self.ffg:=VarArrayCreate([0,0],VarVariant);
  self.MueIm:=VarArrayCreate([0,0],VarVariant);
  self.MueRe:=VarArrayCreate([0,0],VarVariant);
end;

procedure Mue.Assign_Z(Z: Variant);
var Index,i: Integer;
    f: Extended;
begin

  f:=Z*Z;

  for i:=0 to VarArrayHighBound(Z0,1)-1 do
  begin
    if Z > Z0[i] and Z < Z0[i+1then Index:=i;
  end;

  VarArrayInsert(Z0,Index,Z);
  VarArrayInsert(ffg,Index,f);
  VarArrayInsert(MueIm,Index,MueEffIm(Z,Precision));
  VarArrayInsert(MueRe,Index,MueEffRe(Z,Precision));

end;

procedure Mue.Assign_ffg(f: Variant);
var Index,i: Integer;
    Z: Extended;
begin

  Z:=sqrt(f);

  for i:=0 to VarArrayHighBound(ffg,1)-1 do
  begin
    if Z > Z0[i] and Z < Z0[i+1then Index:=i;
  end;

  VarArrayInsert(Z0,Index,Z);
  VarArrayInsert(ffg,Index,f);
  VarArrayInsert(MueIm,Index,MueEffIm(Z,Precision));
  VarArrayInsert(MueRe,Index,MueEffRe(Z,Precision));

end;


An besagter Stelle erzeugt mein Programm jedes mal einen Fehler, wenn ich eine Variable vom Typ Mue deklariere und die Create-Funktion aufrufe. Auf diese Weise habe ich allerdings schon etliche Variant-Arrays erstellt und nie gab es Probleme! Muss ich in einer Klasse anders verfahren, um VarArrayCreate anwenden zu können?


bummi - Mo 07.11.11 21:45

Mach aus


Delphi-Quelltext
1:
Procedure Create();                    


mal


Delphi-Quelltext
1:
Constructor Create();                    


achja ... Klammern fehlen auch


Delphi-Quelltext
1:
 if (Z > Z0[i]) and (Z < Z0[i+1]) then Index:=i;                    


GR-Thunderstorm - Mo 07.11.11 21:57

Das ändert leider nichts. :( Jetzt erzeugt er schon bei

Delphi-Quelltext
1:
Precision:=160;                    


einen Fehler.

EDIT:

Soeben beschriebenes konnte ich korrigieren, indem ich folgendes gemacht habe:


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:
type Mue = class
private
  Precision: Integer;
  Z0: Variant;
  ffg: Variant;
  MueIm: Variant;
  MueRe: Variant;

  procedure Assign_ffg(f: Variant);
  procedure Assign_Z(Z: Variant);
  procedure SetPrecision(X: Integer);

  property Pr: Integer read Precision write SetPrecision;

public
  constructor Create();

  property Z: Variant read Z0 write Assign_Z;
  property f_fg: Variant read ffg write Assign_ffg;
  property Im: Variant read MueIm;
  property Re: Variant read MueRe;
end;

implementation

uses Functions;

procedure TSensor.LO(Z:Integer);
begin
  Lift:=Z;
end;

constructor Mue.Create();
begin
  self.Pr:=160;
  self.Z:=VarArrayCreate([0,0],varVariant); //weiterhin Fehlermeldung hier!
  self.ffg:=VarArrayCreate([0,0],varVariant);
  self.MueIm:=VarArrayCreate([0,0],varVariant);
  self.MueRe:=VarArrayCreate([0,0],varVariant);
end;


Selbiges wollte ich mit Z machen:


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:
procedure Mue.SetPrecision(X: Integer);
begin
  Precision:=X;
end;

procedure Mue.Assign_Z(Z: Variant);
var Index,i: Integer;
    f: Extended;
begin

  if Z = VarArrayCreate([0,0],varVariant) then
  begin
    Z:=VarArrayCreate([0,0],varVariant);
  end
  else
  begin

  f:=Z*Z;

  for i:=0 to VarArrayHighBound(Z0,1)-1 do
  begin
    if Z > Z0[i] and Z < Z0[i+1then Index:=i;
  end;

  VarArrayInsert(Z0,Index,Z);
  VarArrayInsert(ffg,Index,f);
  VarArrayInsert(MueIm,Index,MueEffIm(Z,Precision));
  VarArrayInsert(MueRe,Index,MueEffRe(Z,Precision));
  end;

end;

procedure Mue.Assign_ffg(f: Variant);
var Index,i: Integer;
    Z: Extended;
begin

  Z:=sqrt(f);

  if f = VarArrayCreate([0,0],varVariant) then
  begin
    ffg:=VarArrayCreate([0,0],varVariant);
  end
  else
  begin

  for i:=0 to VarArrayHighBound(ffg,1)-1 do
  begin
    if Z > Z0[i] and Z < Z0[i+1then Index:=i;
  end;

  VarArrayInsert(Z0,Index,Z);
  VarArrayInsert(ffg,Index,f);
  VarArrayInsert(MueIm,Index,MueEffIm(Z,Precision));
  VarArrayInsert(MueRe,Index,MueEffRe(Z,Precision));

  end;

end;


platzwart - Mo 07.11.11 22:10

"einen Fehler", das ist ja äußerst präzise und nun weiß jeder, was das sein könnte... ;)


Blawen - Mo 07.11.11 22:20

user profile iconGR-Thunderstorm hat folgendes geschrieben Zum zitierten Posting springen:
Das ändert leider nichts... Precision:=160;

einen Fehler.
1. Dieser Fehler wird sicher genauer ausgegeben.
2. Vermutlich wird es daran liegen, dass Precision als "Private" deklariert wurde.


GR-Thunderstorm - Mo 07.11.11 22:22

user profile iconBlawen hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconGR-Thunderstorm hat folgendes geschrieben Zum zitierten Posting springen:
Das ändert leider nichts... Precision:=160;

einen Fehler.
1. Dieser Fehler wird sicher genauer ausgegeben.
2. Vermutlich wird es daran liegen, dass die Precision als "Private" deklariert wurde.


Von Class-Membern aus sollte man dennoch darauf zugreifen können. Precision ist ja nun auch nicht länger das Problem. Bei VarArrayCreate([0,0],varVariant) liegt nun der Fehler.

user profile iconplatzwart hat folgendes geschrieben Zum zitierten Posting springen:
"einen Fehler", das ist ja äußerst präzise und nun weiß jeder, was das sein könnte... ;)


"Project GREddy.exe raised exception class EVariantInvalidOpError with message 'Invalid variant operation'. Process stopped. Use Step or Run to continue."


Blawen - Mo 07.11.11 22:25

[OT]Stochern im Nebel :roll: [/OT]


GR-Thunderstorm - Mo 07.11.11 22:27

user profile iconBlawen hat folgendes geschrieben Zum zitierten Posting springen:
[OT]Stochern im Nebel :roll: [/OT]


Titel abgeändert. ;)


Blawen - Mo 07.11.11 22:34

Zitat:
'Invalid variant operation'
Ist schon mal eine brauchbare Aussage.
Allerdings wäre es von Vorteil, wenn auch wir wüssten, wie Deine aktuelle "Baustelle" aussieht (QT-Auzug)


GR-Thunderstorm - Mo 07.11.11 22:38

Je nach Art der Ausführung entweder hier:


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:
constructor Mue.Create();
begin
  self.Pr:=160;
  self.Z:=VarArrayCreate([0,0],varVariant); //--->> Assign_Z
  self.ffg:=VarArrayCreate([0,0],varVariant);
  self.MueIm:=VarArrayCreate([0,0],varVariant);
  self.MueRe:=VarArrayCreate([0,0],varVariant);
end;

procedure Mue.Assign_Z(Z: Variant);
var Index,i: Integer;
    f: Extended;
begin

  if Z = VarArrayCreate([0,0],varVariant) then //Fehlermeldung
  begin
    Z0:=VarArrayCreate([0,0],varVariant);
  end
  else
  begin

  f:=Z*Z;

  for i:=0 to VarArrayHighBound(Z0,1)-1 do
  begin
    if (Z > Z0[i]) and (Z < Z0[i+1]) then Index:=i;
  end;

  VarArrayInsert(Z0,Index,Z);
  VarArrayInsert(ffg,Index,f);
  VarArrayInsert(MueIm,Index,MueEffIm(Z,Precision));
  VarArrayInsert(MueRe,Index,MueEffRe(Z,Precision));
  end;

end;


Oder hier:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
constructor Mue.Create();
begin
  self.Pr:=160;
  self.Z0:=VarArrayCreate([0,0],varVariant); //gleiche Fehlermeldung
  self.ffg:=VarArrayCreate([0,0],varVariant);
  self.MueIm:=VarArrayCreate([0,0],varVariant);
  self.MueRe:=VarArrayCreate([0,0],varVariant);
end;


Edit:

Ich habe das ganze etwas abgewandelt, um die Fehlerhafte If-Anweisung zu vermeiden:


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:
type Mue = class
private
  Precision: Integer;
  Z0: Variant;
  ffg: Variant;
  MueIm: Variant;
  MueRe: Variant;
  InCreation: Boolean;

  procedure Assign_ffg(f: Variant);
  procedure Assign_Z(Z: Variant);
  procedure SetPrecision(X: Integer);
  procedure Assign_MueIm(Mue: Variant);
  procedure Assign_MueRe(Mue: Variant);

  property Pr: Integer read Precision write SetPrecision;

  property CreateMueIm: Variant read MueIm write Assign_MueIm;
  property CreateMueRe: Variant read MueRe write Assign_MueRe;

public
  constructor Create();

  property Z: Variant read Z0 write Assign_Z;
  property f_fg: Variant read ffg write Assign_ffg;
  property Im: Variant read MueIm;
  property Re: Variant read MueRe;
end;

implementation

uses Functions;

procedure TSensor.LO(Z:Integer);
begin
  Lift:=Z;
end;

constructor Mue.Create();
begin
  InCreation:=true;
  self.Pr:=160;
  self.Z:=VarArrayCreate([0,0],varVariant);
  self.f_fg:=VarArrayCreate([0,0],varVariant);
  self.CreateMueIm:=VarArrayCreate([0,0],varVariant);
  self.CreateMueRe:=VarArrayCreate([0,0],varVariant);
  InCreation:=false
end;

procedure Mue.SetPrecision(X: Integer);
begin
  Precision:=X;
end;

procedure Mue.Assign_ffg(f: Variant);
var Index,i: Integer;
    Z: Extended;
begin

  if not InCreation then
  begin
    Z:=sqrt(f);

    for i:=0 to VarArrayHighBound(ffg,1)-1 do
    begin
      if (Z > Z0[i]) and (Z < Z0[i+1]) then Index:=i;
    end;

    VarArrayInsert(Z0,Index,Z);
    VarArrayInsert(ffg,Index,f);
    VarArrayInsert(MueIm,Index,MueEffIm(Z,Precision));
    VarArrayInsert(MueRe,Index,MueEffRe(Z,Precision));
  end
  else ffg:=VarArrayCreate([0,0],VarVariant); //KEIN FEHLER <---- ??????

end;

procedure Mue.Assign_Z(Z: Variant);
var Index,i: Integer;
    f: Extended;
begin

  if not InCreation then
  begin
    f:=Z*Z;

    for i:=0 to VarArrayHighBound(Z0,1)-1 do
    begin
      if (Z > Z0[i]) and (Z < Z0[i+1]) then Index:=i;
    end;

    VarArrayInsert(Z0,Index,Z);
    VarArrayInsert(ffg,Index,f);
    VarArrayInsert(MueIm,Index,MueEffIm(Z,Precision));
    VarArrayInsert(MueRe,Index,MueEffRe(Z,Precision));

  end
  else Z0:=VarArrayCreate([0,0],VarVariant); //FEHLER

end;

procedure Mue.Assign_MueIm(Mue: Variant);
begin
  MueIm:=VarArrayCreate([0,0],varVariant); //FEHLER
end;

procedure Mue.Assign_MueRe(Mue: Variant);
begin
  MueRe:=VarArrayCreate([0,0],varVariant); //FEHLER
end;


Wenn ich einzelne Zeilen aus dem constructor weg-kommentiere, kann ich entsprechend andere Stellen ausführen lassen und jedes mal kommt beim Aufruf von VarArrayCreate die gleiche Fehlermeldung. :(


jaenicke - Mo 07.11.11 23:00

Vermutung:
Du rufst den Konstruktor fälschlicherweise so auf:

Delphi-Quelltext
1:
2:
3:
4:
var
  xyz: TMue;
begin
  xyz.Create;
Self ist dann im Konstruktor gar nicht definiert, da es die uninitialisierte Variable xyz ist. Und deshalb knallt es.

Nebenbei:
Es ist Konvention, dass ein Klassenname immer mit T beginnt.


GR-Thunderstorm - Mo 07.11.11 23:04

Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Hmm nunja, es wird skuriler:

Ich habe herausgefunden, dass diese Zeile KEINEN Fehler verursacht:


Delphi-Quelltext
1:
ffg:=VarArrayCreate([0,0],VarVariant);                    


Wegen der Konvention: Das werde ich dann mal abändern. :)

Edit:

Ich habe den Fehler gefunden. >.< Ich wusste erst nicht so genau, was Jaenicke mir mit dem Post sagen wollte. ^^


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//falsch:

var Test: TMue;
begin
  Test.Create();
end;

//richtig:

var Test: TMue;
begin
  Test:=TMue.Create();
end;


Das erklärt zwar nicht, wieso auf "ffg" zugegriffen werden konnte und auf "Z0" nicht, aber nun klappt alles wunderbar. :)

Vielen Dank für die Hilfe (und vor allem Geduld! :D) an euch alle!


jaenicke - Di 08.11.11 06:51

user profile iconGR-Thunderstorm hat folgendes geschrieben Zum zitierten Posting springen:
Das erklärt zwar nicht, wieso auf "ffg" zugegriffen werden konnte und auf "Z0" nicht
Reiner Zufall. ;-)
Da du auf die Methode Create des (uninitialisierten) Objekts statt auf den Konstruktor der Klasse zugegriffen hast, hast du dort auf zufällige Stellen im Speicher zugegriffen. Und das knallt eben mal und mal nicht sofort.