Forum > Beginners
<Solved> Problem: class; virtual method; runtime Exception "External: SIGSEGV"
oog:
I am implementing a simple microprocessor as a class and a computer as a derived (child) class of microprocessor.
The computer implements memory like ram/rom that should be read by the microprocessor, but I can't get it to work.
This simplified program shows the problem. I think I'm handling virtual methods in a wrong way.
Problem 1:
If the method readmem() is not virtual, i get the wrong memory content.
Problem 2:
If I declare the method readmem() as virtual / override, I get a runtime Exception "External: SIGSEGV".
The simple test program uses a form with Memo1, Butto1 und Button2.
This is the result pushing Button1 and Button2 without virtual methodes:
Memo1:
Expect same result for mem and cpu.
Processor: mem=0 cpu=0
Computer: mem=1 cpu=0
I expect this: Computer: mem=1 cpu=1
Here is the code of the complete unit:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit unit7; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls; type { TForm7 } TForm7 = class(TForm) Button1: TButton; Button2: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormCreate(Sender: TObject); private public end; // class Processor (base class) typeTProcessor = classprivatepublic constructor init; //destructor kill; function readmem(): integer; virtual; function runcpu: integer;end; // class Computer (child of processor) typeTComputer = class(TProcessor)privatepublic constructor init; //destructor kill; function readmem(): integer; override;end; var Form7: TForm7; Processor: TProcessor; Computer: TComputer; implementation {$R *.lfm} { TForm7 } procedure TForm7.Button1Click(Sender: TObject);var m,c: integer;begin m:=Processor.readmem(); // this is the content of ram c:=Processor.runcpu; // this is read by the cpu (should be the same) Memo1.Lines.Add('Processor:' +' mem='+IntToStr(m) +' cpu='+IntToStr(c) );end; procedure TForm7.Button2Click(Sender: TObject);var m,c: integer;begin m:=Computer.readmem(); // this is the content of ram c:=Computer.runcpu; // this is read by the cpu (should be the same) Memo1.Lines.Add('Computer:' +' mem='+IntToStr(m) +' cpu='+IntToStr(c) );end; procedure TForm7.FormCreate(Sender: TObject);begin Memo1.Clear; Memo1.Lines.Add('Expect same result for mem and cpu.'); Processor.init; Computer.init;end; ////////////////////////////////////////// object Processor//////////////////////////////////////// constructor TProcessor.init;beginend; //destructor TProcessor.kill;//begin//end; function TProcessor.readmem(): integer;begin readmem:=0;end; function TProcessor.runcpu: integer;begin runcpu:=readmem();end; ////////////////////////////////////////// object Computer//////////////////////////////////////// constructor TComputer.init;begin inherited; TProcessor.init;end; //destructor TComputer.kill;//begin//end; function TComputer.readmem(): integer;begin readmem:=1;end; end.
Eugene Loza:
Note that you are using obsolete OOP from Turbo Pascal. Note that class is not the same thing as object.
Classes need to operate on "instances". I.e. a specific self-contained object which in reality is a reference to memory volume (data) and methods on how to operate it.
In other words:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type TMyClass = class public A; virtual;end; var MyClass: TMyClass;begin MyClass.Init; MyClass.A;end;
Is not correct. A is a method that needs to operate on an "instance", and therefore calling it on class "type" may and will result in unexected behavior. The fact that A is virtual makes things only worse - as virtual methods not just operate on some abstract memory volume, but operate on a specific instance of a class which you don't provide.
So, what happens above is MyClass (in your case Processor) variable is nil. Nil is a reference to "nowhere", meaning that the instance doesn't exist. Some methods may survive being called on a nil instance. But virtual methods that must know about what instance they are called on (to know what exact child of the method must be called) cannot do that and hence the error.
Again, the confusion comes from old objects which were rather like (advanced) records, i.e. were automatically allocated on heap memory and therefore didn't need any additional memory management to make sure the variable is pointing to a valid instance of a class.
So, the new way of handling objects is this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type TMyClass = class public A; virtual;end; var MyClass: TMyClass; // this is a reference to an instance of the classbegin MyClass := TMyClass.Create; // create an instance of the class and assign it to the variable pointing to the instance of the class MyClass.A; // call method of this specific instance; MyClass.Free; // finally release memory occupied by the classend;
I must admit that a few years ago I myself had been struggling with this specific problem :D And this short book helped me greatly to switch from Turbo Pascal to modern Pascal way of thinking https://castle-engine.io/modern_pascal
cdbc:
Hi
@Eugene Loza beat me to it...
His response is more thorough than mine... but I'll leave it, anyway...
First off, creation goes like this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm7.FormCreate(Sender: TObject);begin Memo1.Clear; Memo1.Lines.Add('Expect same result for mem and cpu.'); Processor:= TProcessor.init; // we usually call 'init' for 'Create' Computer:= TComputer.init; // we usually call 'init' for 'Create'end;...and you HAVE to Free / Destroy them again, when done, like this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm7.FormDestroy(Sender: TObject);begin Processor.Free; // Free calls 'Destroy' internally, Computer.Free; // after checking for NILend;As shown, the 'OnDestroy' event-handler is good for that
Your AV came from not creating your objects before use.
HTH
Regards Benny
oog:
Thank you very much for this explanation.
This looks very helpful.
:D :D :D
oog:
Now it works, thank you all. :D
The result by pushing Button1 and Button2 is now, what I expected:
Memo1:
Expect same result for mem and cpu.
Processor: mem=0 cpu=0 (by puhing Button1)
Computer: mem=1 cpu=1 (by puhing Button2)
This small example program compiles and runs well as it should. Constructor and destructor are in the comments. The program uses a Form with Button1, Button2 and Memo1 Here is the code:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit unit7; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls; type { TForm7 } TForm7 = class(TForm) Button1: TButton; Button2: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private public end; // class Processor (base class) typeTProcessor = classprivatepublic //constructor init; //destructor free; function readmem(): integer; virtual; function runcpu: integer;end; // class Computer (child of processor) typeTComputer = class(TProcessor)privatepublic function readmem(): integer; override;end; var Form7: TForm7; Processor: TProcessor; Computer: TComputer; implementation {$R *.lfm} { TForm7 } procedure TForm7.Button1Click(Sender: TObject);var m,c: integer;begin m:=Processor.readmem(); // this is the content of ram c:=Processor.runcpu; // this is read by the cpu (should be the same) Memo1.Lines.Add('Processor:' +' mem='+IntToStr(m) +' cpu='+IntToStr(c) );end; procedure TForm7.Button2Click(Sender: TObject);var m,c: integer;begin m:=Computer.readmem(); // this is the content of ram c:=Computer.runcpu; // this is read by the cpu (should be the same) Memo1.Lines.Add('Computer:' +' mem='+IntToStr(m) +' cpu='+IntToStr(c) );end; procedure TForm7.FormCreate(Sender: TObject);begin Memo1.Clear; Memo1.Lines.Add('Expect same result for mem and cpu.'); Processor:=TProcessor.Create; Computer:=TComputer.Create; //Processor.init; //Computer.init;end; procedure TForm7.FormDestroy(Sender: TObject);begin //Processor.Free; //Computer.Free;end; ////////////////////////////////////////// class Processor//////////////////////////////////////// //constructor TProcessor.init;//begin//end;//////destructor TProcessor.free;//begin//end; function TProcessor.readmem(): integer;begin readmem:=0;end; function TProcessor.runcpu: integer;begin runcpu:=readmem();end; ////////////////////////////////////////// class Computer//////////////////////////////////////// //constructor TComputer.init;//begin//end;//////destructor TComputer.free;//begin//end; function TComputer.readmem(): integer;begin readmem:=1;end; end.
Navigation
[0] Message Index
[#] Next page