views:

189

answers:

3

I have a binary tree class that is created with a root node and nodes can be added to it as needed in the code, however I am having trouble in deleting the nodes because I point to them with TNodePtr and it is an incompatible type with TNode. At the moment I have this recursive method of deleing nodes which should work once the incompatible types is sorted. Thanks.

Destructor TTree.Destroy;
procedure FreeSubnodes(Node: TNodePtr);
begin
        if Assigned(Node.Left) then
                FreeSubnodes(Node.Left);
        if Assigned(Node.Right) then
                FreeSubnodes(Node.Right);
        Delete(Node);
end;
begin
        FreeSubnodes(Root);
        inherited;
end;

Edit 04/03/2010: The error given is this: [Warning] SystemBuild.pas(50): Method 'Destroy' hides virtual method of base type 'TObject' [Error] SystemBuild.pas(84): Incompatible types

Line 84 is Delete(Node);

I declared the node like this:

type
    TNodePtr = ^TNode;
    TNode = Record
        Data:String;
        Left:TNodePtr;
        Right:TNodePtr;
    end;

And the tree like this:

Type
    TTree = Class
    Private
        Root:TNodePtr;
    Public
        Function GetRoot:TNodePtr;
        Constructor Create;
        Destructor Destroy;
    end;
A: 

to dereference the pointer use Node^

luca
Depending on the Delphi version this is done "automagically" by the compiler.
DR
The version of Delphi I am using is Delphi7, dont know if that affects anything though.
NeoNMD
+1  A: 
Destructor TTree.Destroy;
    procedure FreeSubnodes(Node: TNodePtr);
    var
        ThisNode:TNode;
    begin
        ThisNode := Node^;
            if Assigned(ThisNode.Left) then
                    FreeSubnodes(ThisNode.Left);
            if Assigned(ThisNode.Right) then
                    FreeSubnodes(ThisNode.Right);
            Dispose(Node);
    end;
begin
        FreeSubnodes(Root);
        inherited;
end;
JamesB
+3  A: 

The error you see is because of a mistake I made in the answer I gave to your previous question. I wrote Delete when I should have written Dispose. I apologize. Here, then, is the correct destructor implementation:

destructor TTree.Destroy;
  procedure FreeSubnodes(Node: PNode);
  begin
    if Assigned(Node.Left) then
      FreeSubnodes(Node.Left);
    if Assigned(Node.Right) then
      FreeSubnodes(Node.Right);
    Dispose(Node);
  end;
begin
  FreeSubnodes(Root);
  inherited;
end;

The error is not saying that TNodePtr is incompatible with TNode. The error just says "incompatible types" because the compiler doesn't know what type Delete is supposed to receive. It's a compiler-magic function that accepts several different parameter types, none of which is compatible with TNodePtr.

The first compiler message you see is about your Destroy method hiding the method from the base class. It's not responsible for the problem you were seeing, but you'd eventually notice a problem because your destructor would never get called. When you call Free, it will call TObject's Destroy method, not your new version. To make yours get called instead, you need to mark yours as overriding the inherited version. Then, when TObject.Free calls Destroy, control will go to your version first, and then go to the base class's version when you call inherited. Change the declaration to this:

destructor Destroy; override;
Rob Kennedy
I looked back and it seems you didnt make a mistake in the original code. It does infact say "Dispose" the first time. I have since changed all my loops to be recursive though to make it simpler and I then used a recursive destructor but it appears I made it wrong clearly.Is it neccessary to have this bit?"if assigned (root.left) then FreeSubnodes(Root.Left); if Assigned(Root.Right) then FreeSubnodes(Root.Right); inherited;"Because the inside of the destructor will get to root.left and root.right anyway...
NeoNMD
There is no recursive destructor. There's only one object here, the TTree object. Your nodes aren't objects; they don't have destructors. If you changed Root's declaration to be TNode, then you need to free Root.Left and Root.Right separately because FreeSubnodes can't be called on Root itself.
Rob Kennedy
It *did* say Delete before. I discovered the problem as I was writing the first version of this answer. I went back and fixed the mistake in the previous answer so everyone else who encounters it in the future won't get stuck with bad code. I also changed this answer to put more emphasis on the fact that it was due to my mistake instead of speculating on all the things you might have changed, but didn't.
Rob Kennedy
I have so much to learn still. :)Thanks for the help yet again, you are a legend.Also I did try destructor Destroy Override; before but I must have missed the semicolon. We have not been taught about overriding or inheriting in delphi, we only learned the theory on it so far.
NeoNMD