Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - AccessViolation beim Ausführen des Programms


FlySource - Mi 30.05.12 21:40
Titel: AccessViolation beim Ausführen des Programms
Hallo User!

Ich habe hier mal ein neues Thema geöffnet, weil ich nichts passendes gefunden habe, zudem hoffe ich, dass ich im richtigen Unterforum gelandet bin.

Ich schreibe im Moment an einem Programm, das Bücherdaten verwaltet auf Basis einer TList.
Mein Problem liegt darin, dass ich die komplette Bücherdatenbank löschen will und zwar mit dem destructor destroy aus uTDatenbank, aber das Programm mir den Fehler anzeigt:

uTBuecherdatenbank.pas(23): Methode 'Destroy' verbirgt virtuelle Methode vom Basistyp 'TObject'

Ich habe keine Ahnung was ich mit dem Fehler anfangen soll und woran es liegt.


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:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
UNIT uTBuecherdatenbank;

interface

//--------------------  ggf Uses-Liste einfügen !  --------------------
uses mList, uTBuch, SysUtils;

type
  TBuecherdatenbank = class

  protected //Attribute
    dieListe : TList;

  public //Methoden
    constructor create; virtual;
    procedure buchEinfuegen (pBuch: TBuch); virtual;
    procedure buchLoeschen (pISBN: string); virtual;
    procedure buchVerkaufen (pISBN: string); virtual;
    procedure setzeAufErstes; virtual;
    function gibISBN (pAutor: string; pTitel: string) : stringvirtual;
    function gibNaechstes : stringvirtual;
    function gibPreis (pISBN: string) : integer; virtual;
    destructor destroy;virtual;

   end;

implementation

//+---------------------------------------------------------------------
//|         TBuecherdatenbank: Methodendefinition 
//+---------------------------------------------------------------------

//-------- create (public) ---------------------------------------------
constructor TBuecherdatenbank.create;
begin
  dieListe := TList.create;
end;

//-------- buchEinfuegen (public) --------------------------------------
procedure TBuecherdatenbank.buchEinfuegen (pBuch: TBuch);
var hilfsobjekt: TBuch;
  fertig: boolean;
begin
  //  dieListe.append(pBuch);
  fertig:=false;
  dieListe.toFirst; // aktuelles Objekt soll auf das erste Objekt zeigen

  while dieListe.hasAccess = true do // solange noch "was da" ->nicht am Ende
  begin
      hilfsobjekt:=TBuch(dieListe.getObject);
      if hilfsobjekt.GibISBN > pBuch.GibISBN then
      begin
        dieListe.insert(pBuch); // fügt Buch an richtiger Stelle ein
        fertig:=true;
        break; // da Buch eingefügt, sofort aufhören (while-Schleife verlasen)
      end;
      dieListe.next;
  end;
  if fertig=false then dieListe.append(pBuch);

end;

//-------- buchLoeschen (public) ---------------------------------------
procedure TBuecherdatenbank.buchLoeschen (pISBN: string);
var hilfsobjekt: TBuch;
begin
  dieListe.toFirst;
  while dieListe.hasAccess = true do
  begin
    hilfsobjekt := TBuch(dieListe.getObject);
    if (hilfsobjekt.GibISBN = pISBN) then
    begin
      dieListe.remove;
      break;
    end;
    dieListe.next;
  end;
end;

//-------- buchVerkaufen (public) --------------------------------------
procedure TBuecherdatenbank.buchVerkaufen (pISBN: string);
var hilfsobjekt: TBuch;
    anz: integer;
begin
  // Zeiger aufs erste Objekt
  dieListe.toFirst;

  // solange next ausführen bis Buch mit passender ISBN gefunden
  // solange noch nicht am Ende
  while dieListe.hasAccess = true do
  begin
    hilfsobjekt := TBuch(dieListe.getObject);

    // wenn isbn gleich dann
    if hilfsobjekt.GibISBN = pISBN then
    begin
      anz := hilfsobjekt.GibAnzahl;
      anz := anz-1;
      hilfsobjekt.SetzeAnzahl(anz);
      dieListe.setObject(hilfsobjekt);

      break; // gefunden, also fertig -> springt aus while-Schleife
    end;
    dieListe.next;
  end;
end;

//-------- setzeAufErstes (public) -------------------------------------
procedure TBuecherdatenbank.setzeAufErstes;
begin
  dieListe.toFirst;
end;

//-------- gibISBN (public) --------------------------------------------
function TBuecherdatenbank.gibISBN (pAutor: string; pTitel: string) : string;
var hilfsobjekt: TBuch;
begin
  dieListe.toFirst;
  gibISBN:='nicht vorhanden';
  while dieListe.hasAccess = true do
  begin
    hilfsobjekt := TBuch(dieListe.getObject);
    if (hilfsobjekt.GibAutor = pAutor)
                          and (hilfsobjekt.GibTitel = pTitel) then
    begin
      gibISBN:=hilfsobjekt.GibISBN;
      break;
    end;
    dieListe.next;
  end;
end;

//-------- gibNaechstes (public) ---------------------------------------
function TBuecherdatenbank.gibNaechstes : string;
var hilfstring: string;
    hilfsobjekt: TBuch;
begin
  if dieListe.hasAccess=true then
  begin
    hilfsobjekt := TBuch(dieListe.getObject);
    hilfstring := hilfsobjekt.GibTitel + '; ' +
                  hilfsobjekt.GibAutor + '; ' +
                  hilfsobjekt.GibISBN + '; ' +

             inttostr(hilfsobjekt.GibPreis) + '; ' +
             inttostr(hilfsobjekt.GibAnzahl);
    dieListe.next;
    gibNaechstes:=hilfstring;
  end
  else gibNaechstes:='';

end;

//-------- gibPreis (public) -------------------------------------------
function TBuecherdatenbank.gibPreis (pISBN: string) : integer;
var hilfsobjekt: TBuch;
begin
  dieListe.toFirst;
  gibPreis:=0;
  while dieListe.hasAccess = true do
  begin
    hilfsobjekt := TBuch(dieListe.getObject);
    if (hilfsobjekt.GibISBN = pISBN) then
    begin
      gibPreis:=hilfsobjekt.GibPreis;
      break;
    end;
    dieListe.next;
  end;
end;

//-------- destroy (public) --------------------------------------------
destructor TBuecherdatenbank.destroy;
begin
dieliste.toFirst;
while dieliste.hasAccess=true do
begin
dieliste.remove;
dieliste.next;
if dieliste.hasAccess=false then
break;
end;
end;



end.


Die vorgegebene Liste:


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:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
(*
 * Materialien zu den zentralen Abiturpruefungen
 * im Fach Informatik ab 2012 in Nordrhein-Westfalen.
 *
 * Klasse TList
 *
 * NW-Arbeitsgruppe:
 * Materialentwicklung zum Zentralabitur im Fach Informatik
 *
 * Version 2010-12-28
 *)


UNIT mList;

interface
type
  TNode = class
 private
    content: TObject;
    nextNode: TNode;
    constructor create(pObject: TObject);
    procedure setContent(pObject: TObject);
    procedure setNext(pNext: TNode);
    function getContent: TObject;
    function getNext: TNode;
    destructor destroy; override;
  end;

  TList = class
  private
    first: TNode;
    tail: TNode;
    current: TNode;
   public
     constructor create; virtual;
     function isEmpty: boolean; virtual;
     function hasAccess: boolean; virtual;
     procedure next; virtual;
     procedure toFirst; virtual;
     procedure toLast; virtual;
     function getObject: TObject; virtual;
     procedure setObject(pObject: TObject); virtual;
     procedure append(pObject: TObject); virtual;
     procedure insert(pObject: TObject); virtual;
     procedure concat(pList: TList); virtual;
     procedure remove; virtual;
     destructor destroy; override;
   end;

implementation

// TNode

constructor TNode.create(pObject: TObject);
begin
  content := pObject;
  nextNode := nil;
end;

procedure TNode.setContent(pObject: TObject);
begin
  content := pObject;
end;

procedure TNode.setNext(pNext: TNode);
begin
  nextNode := pNext;
end;

function TNode.getContent: TObject;
begin
  result := content;
end;

function TNode.getNext: TNode;
begin
  result := nextNode;
end;

destructor TNode.destroy;
begin
  inherited destroy;
end;

// TList

constructor TList.create;
begin
  tail := TNode.create(nil); // dummy
  first := tail;
  tail.setNext(tail); // dummy.next toLast
  current := first;
end;

function TList.isEmpty: boolean;
begin
  result := first = tail;
end;

function TList.hasAccess: boolean;
begin
  result := not self.isEmpty and (current <> tail);
end;

procedure TList.next;
begin
  if self.hasAccess then
    current := current.getNext;
end;

procedure TList.toFirst;
begin
  if not self.isEmpty then
    current := first;
end;

procedure TList.toLast;
begin
  if not self.isEmpty then
    current := tail.getNext;
end;

function TList.getObject: tObject;
begin
  if self.hasAccess then
    result := current.getContent
  else
    result := nil;
end;

procedure TList.setObject(pObject: TObject);
begin
  if (pObject <> niland self.hasAccess then
    current.setContent(pObject)
end;

procedure TList.insert(pObject: TObject);
var
  currentPos, aktPos, newNode, frontNode:TNode;
begin
  if pObject <> nil then
  begin
    if self.isEmpty then
      self.append(pObject)
    else
    begin
      if self.hasAccess then
      begin
        currentPos := current;
        aktPos := current;
        newNode := TNode.create(pObject);
        newNode.setNext(current);
        if aktPos = first then
          first := newNode
        else
        begin
          self.toFirst;
          frontNode := current;
          while self.hasAccess and (current <> aktPos) do
          begin
            frontNode := current;
            self.next;
          end;
          frontNode.setNext(newNode);
        end;
        current := currentPos;
      end;
    end;
  end;
end;

procedure TList.append(pObject: TObject);
var
  currentPos, newNode, previousNode: TNode;
begin
  if pObject <> nil then
  begin
    currentPos := current;
    newNode := TNode.create(pObject);
    newNode.setNext(tail);
    if self.isEmpty then
      first := newNode
    else
    begin
      previousNode := tail.getNext;
      previousNode.setNext(newNode);
    end;
    tail.setNext(newNode);
    current := currentPos;
  end;
end;

procedure TList.concat(pList: TList);
var
  currentPos,lastNode,dummy: TNode;
begin
  if (pList <> niland not pList.isEmpty then
  begin
    if self.isEmpty then
    begin
      first := pList.first;
      tail := pList.tail;
      current := tail;
    end
    else
    begin
      currentPos := current;
      lastNode := tail.getNext;
      tail := pList.tail;
      dummy := lastNode.nextNode;
      lastNode.setNext(pList.first);
      if currentPos = dummy then
        current := tail
      else
       current := currentPos;
      dummy.destroy;
    end;
      pList.tail := TNode.create(nil);
      pList.first := pList.tail;
      pList.tail.setNext(pList.tail);
      pList.current := pList.first;
  end;
end;

procedure TList.remove;
var
  currentPos, markPos, frontPos: TNode;
begin
  if not self.isEmpty and self.hasAccess then
  begin
    currentPos := current;
    if current = first then
    begin
      first := current.getNext;
      if current.getNext = tail then
        tail.setNext(first);
      current := first;
    end else
    begin
      markPos := current;
      self.toFirst;
      frontPos := current;
      while self.hasAccess and (current <> markPos) do
      begin
        frontPos := current;
        self.next;
      end;
      frontPos.setNext(markPos.getNext);
      current := frontPos.getNext;
      if current = tail then
        tail.setNext(frontPos);
    end;
    currentPos.destroy;
  end;
end;


destructor TList.destroy;
begin
  while not self.isEmpty do
  begin
    self.toFirst;
    self.remove;
  end;
  tail.destroy;
  inherited destroy;
end;

end.


So habe ich mir vorgestellt soll das Programm darauf zugreifen:


Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TForm1.Button6Click(Sender: TObject);
begin
  db.destroy;
  ausgabe;
end;



hier ist die Klasse Fachbuch, die noch nicht angelegt wurde, sondern nur da ist, damit man es in der GUI aufrufen kann


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:
UNIT uTFachbuch;

interface

//--------------------  ggf Uses-Liste anpassen !  --------------------
uses uTBuch;

type
  TFachbuch = class(TBuch)

  protected //Attribute
    Kategorie : string;

  public //Methoden
    constructor create (pAnzahl: integer; pPreis: integer; pAutor: string; pISBN: string; pTitel: string; pKategorie: string); virtual;
    function GibKategorie : stringvirtual;

   end;

implementation

//+---------------------------------------------------------------------
//|         TFachbuch: Methodendefinition 
//+---------------------------------------------------------------------

//-------- create (public) ---------------------------------------------
constructor TFachbuch.create (pAnzahl: integer; pPreis: integer; pAutor: string; pISBN: string; pTitel: string; pKategorie: string);
begin
  anzahl:=pAnzahl;
  preis:=pPreis;
  autor:=pAutor;
  isbn:=pISBN;
  titel:=pTitel;
  kategorie:=pKategorie;
end;

//-------- GibKategorie (public) ---------------------------------------
function TFachbuch.GibKategorie : string;
begin
  result  := Kategorie
end;

end.


und ich weiß nicht ob man das noch zum Verständnis braucht:


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:
UNIT uTBuch;

interface

//--------------------  ggf Uses-Liste einfügen !  --------------------
//uses ....;

type
  TBuch = class(TObject)

  protected //Attribute
    Anzahl : integer;
    Preis : integer;
    Autor : string;
    ISBN : string;
    Titel : string;

  public //Methoden
    procedure create; virtual;
    procedure SetzeAnzahl (pAnzahl: integer); virtual;
    function GibAnzahl : integer; virtual;
    function GibAutor : stringvirtual;
    function GibISBN : stringvirtual;
    function GibPreis : integer; virtual;
    function GibTitel : stringvirtual;
    destructor destroy; virtual;

   end;

implementation

//+---------------------------------------------------------------------
//|         TBuch: Methodendefinition 
//+---------------------------------------------------------------------

//-------- create (public) ---------------------------------------------
procedure TBuch.create;
begin
  //hier ggf. Code ergänzen
end;

//-------- SetzeAnzahl (public) ----------------------------------------
procedure TBuch.SetzeAnzahl (pAnzahl: integer);
begin
  Anzahl := pAnzahl
end;

//-------- GibAnzahl (public) ------------------------------------------
function TBuch.GibAnzahl : integer;
begin
  result := Anzahl
end;

//-------- GibAutor (public) -------------------------------------------
function TBuch.GibAutor : string;
begin
  result := Autor
end;

//-------- GibISBN (public) --------------------------------------------
function TBuch.GibISBN : string;
begin
  result  := ISBN
end;

//-------- GibPreis (public) -------------------------------------------
function TBuch.GibPreis : integer;
begin
  result := Preis
end;

//-------- GibTitel (public) -------------------------------------------
function TBuch.GibTitel : string;
begin
  result  := Titel
end;

//-------- destroy (public) --------------------------------------------
destructor TBuch.destroy;
begin
  //hier ggf. Code ergänzen
end;

end.



Ich hoffe, das ist alles richtig so.

LG Fly


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Mi 30.05.2012 um 22:26


glotzer - Mi 30.05.12 22:01

Hallo und wilkommen :D

der Fehler ist ganz einfach:

statt destructor destroy;virtual; einfach destructor destroy;override; und alles sollte funktionieren.


FlySource - Mi 30.05.12 22:42

Ja, schön wäre es, wenn das so einfach funktionieren würde, allerdings, behebt es das Problem an sich nicht, denn es kommt wieder eine Zugriffsverletzung wenn man das Programm ausführt, diesen Vorschlag habe ich nämlich auch schon ausprobiert, es ist wahrscheinlich nur eine dumme Kleinigkeit, aber ich komme nicht drauf, den falsch programmiert scheint das destroy nicht zu sein, zumindest nicht in meinen Augen.

MfG


Lemmy - Mi 30.05.12 23:29

user profile iconFlySource hat folgendes geschrieben Zum zitierten Posting springen:
denn es kommt wieder eine Zugriffsverletzung wenn man das Programm ausführt


verrätst Du uns auch wo die Zugriffsverletzung kommt (Stichwort Debugger) oder sollen wir raten? ;-)

Grüße


FlySource - Do 31.05.12 07:02

Ja na klar, also wenn ich das Programm starte, es dann abstürtzt, bleibt es immer bei der procedure buttonclick6 in der büchergui hängen, so wie es aussieht.
Ich hoffe es ist die Information, die gesucht war.

Grüße


jaenicke - Do 31.05.12 07:06

Erstens sollte man immer Objekt.Free oder FreeAndNil(Objekt) verwenden, zweitens ist dir hoffentlich klar, dass du nach db.Destroy auch nicht mehr auf db zugreifen darfst ohne es neu zu erzeugen. (Passiert in ausgabe vielleicht ein Zugriff auf db? ;-))

Bei welcher Zeile kommt denn die Schutzverletzung? Setze doch einfach mal einen Haltepunkt (F5) auf das (dann hoffentlich schon ersetzte ;-)) db.Destroy, starte das Programm und gehe schrittweise durch (F7), wenn das Programm dort ankommt. Wo passiert der Fehler?


FlySource - Do 31.05.12 14:05

So naja ich habe mal durchgeschaut und ja es war das Problem mit der Ausgabe ^^

Naja ich habs jetzt so gemacht, dass die datenbank gelöscht wird, dass muss sie ja, weil auf sie ja nicht mehr zugegriffen werden konnte oder sehe ich das falsch?

Dann habe ich anstatt die Listbox mit der db zu überschreiben, was ja nicht ging einfach auf listbox1.clear gesetzt.

Das angeprochene Objekt.free oder freeandnil hatten wir bisher noch nicht im Unterricht von daher, meide ich meist immer das was wir nicht im Unterricht machen, weil wir ja auch mit den uns bekannten Methoden die Arbeit schreiben.


jaenicke - Do 31.05.12 14:15

user profile iconFlySource hat folgendes geschrieben Zum zitierten Posting springen:
Das angeprochene Objekt.free oder freeandnil hatten wir bisher noch nicht im Unterricht von daher, meide ich meist immer das was wir nicht im Unterricht machen, weil wir ja auch mit den uns bekannten Methoden die Arbeit schreiben.
Du kannst deinem Lehrer ja mal die Hilfe zu Destroy zeigen. ;-)
http://docwiki.embarcadero.com/Libraries/de/System.TObject.Destroy hat folgendes geschrieben:
Rufen Sie Destroy nicht direkt auf. Verwenden Sie stattdessen Free.
Das so erst zu lernen ist nicht schön...


FlySource - Do 31.05.12 14:47

Naja was heißt schon lernen, er hat halt gesagt, weil er im Stress war, macht das mal und naja wir haben das halt noch nicht besprochen und morgen schreiben wir halt Klausur, und da wir nicht an ein und derselben Schule Info haben, hab ich ihn heute auch nicht angetroffen...

Hauptsache ist halt, dass es von der Sache her richtig programmiert ist und die Oberfläche ist in der Arbeit meist nicht so wichtig, weil die aufm papier eh schwer darzustellen ist, dann muss man noch mehr aufpassen, wo man was hat ^^