?
Solved

Inheritance, VMT an so on...

Posted on 2003-03-20
9
Medium Priority
?
152 Views
Last Modified: 2010-04-04
Hi Xperts,

Although I'm into Delphi for a couple of years I'm still a little bit confused about the Delphi object stuff. As far as I know (and maybe I'm wrong) a constructor has to do the following:
- Allocate memory for the member variables
- Execute code of the "constructor procedure"
- Do some VMT stuff
And here my problem goes:
Assume you have a base type TBaseClass and a derived type TMyClass. This leads to something like

constructor TMyClass.Create;
begin
  inherited;
  SomeCode;
end;

destructor TMyClass.Destroy;
begin
  inherited;
end;

You have to get memory for the members of TBaseClass and the members of TMyClass. Dito for the VMT. What happens to the members and VMT of the base class if you do it like this

constructor TMyClass.Create;
begin
  // inherited;
  SomeCode;
end;

And what about that:

  myVar_1 := TMyClass.Create;
  myVar_2 := myVar_1.Create;

What if the constructors are virtual?

I hope you've understood what I'm asking for. If there is more than one good comments I will provide more points in an extra thread!

Thank you in advance!
0
Comment
Question by:j42
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
9 Comments
 
LVL 1

Expert Comment

by:soapsiam
ID: 8173105
VMT is specific for each class not object (instance of the class). So there is only one VMT per class and there is a pointer to base class's VMT (in case of root class like TObject pointer to Ancestor VMT is NIL). Thus there is notthing with VMT. If you call
  obj := TMyClass.Create;

  First the constructor of TMyClass was called, then in the constor of TMyClass, Ancestor's constructor was called (denoted by inherited reserved word).

myVar_1 := TMyClass.Create; // Delphi way of constructor called to create instance of that class
 myVar_2 := myVar_1.Create;

Virtual means you can override it in descendant class.

Hope you understand me...
0
 
LVL 2

Author Comment

by:j42
ID: 8173501
Hi soapsiam,

thanks for answering! I guess you want to provide some basic information about OOP but the information I need is "a little bit more technical" (sorry, it is so hard for me to explain that in english sometimes):

> Thus there is notthing with VMT. If you call
>   obj := TMyClass.Create
If you do not call TMyClass.Create at any time in your application there is no need for the linker to create a VMT for TMyClass

> First the constructor of TMyClass was called, then in
> the constor of TMyClass, Ancestor's constructor was
> called (denoted by inherited reserved word).
But what if I omit the inherited key word? What exactly will be omitted? The code you can see between "begin" and "end;" of TBaseClass.Create? What else?

> myVar_1 := TMyClass.Create; // Delphi way of constructor called to create instance of that class
> myVar_2 := myVar_1.Create;
The second line is valid (even though not very usual). myVar_2 will contain adress of myVar_1. But what else happens, any memory allocation???



Regards
(I hope this is not to confusing)
0
 
LVL 12

Expert Comment

by:andrewjb
ID: 8182186

When you call a constructor using a class reference
e.g. TMyClass.Create
the compiler provides you with the appropriate amount of memory for the object, and then calls the constructor.

You can actually call the constructor using an object reference. In this case, the compiler does NOT allocate the memory - you're really just calling a method of the object

so var X : tMyClass;

X = .... something

X.Create - is valid, but just calles the 'Create' method in teh same was as any other procedure or function.


When you use inherited within a constructor, it means 'call the parent's method with the same name as this one'

So it's like calling Self.Create, but making sure you get the parent class's constructor and not yours.

So, if you don't call 'inherited', you still get all the appropriate memory allocated for the class itself, but won't get any parent constructors called.

This matters if the parent constructor creates some objects iteself, or initialises variables

e.g.

tBaseClass
  private:
    fList : tStringList;

constructor tBaseClass.Create()
begin
  fList := tStringList.Create;
end;


tSubClass = class(tBaseClass)
...

constructor tSubClass.Create()
begin
 ... do stuff
  inherited; //// ****
end;

if i don't use 'inherited', then the fList won't get created and that's going to mess things up later...
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Author Comment

by:j42
ID: 8193790
Hi andrewjb,

thank you, the penny has dropped! As I understood, you can omit the inherited in the constructor as long as you know what you do. But what about the destructor? I do not think it possible to call it like a 'normal' procedure/function?
Can you tell me any reason why the destructor is virtual if you use the code insight feature.
Can you tell me why the 'inherited' never is omitted if you use class completion (Ctrl-Shift-C)?
Thanks so far (you really helped me a lot)!



Regards
J
0
 
LVL 12

Expert Comment

by:andrewjb
ID: 8194308
The destructor is similar, in a way. Calling a destructor runs the code you've written, then 'magically' frees off the memory allocated for the object. You don't have to call the inherited destructor. If you don't, the memory is still freed off properly, but code written in inherited destructors are not.
This is a problem if one of those inherited destructors is freeing off something extra itself. Back to the example of a tStringList. If the base class constructor is doing
fList = tStringList.Create;
then this is creating a new object. You therefore need to free this off in the destructor
destructor tBaseClass.Destroy;
begin
  fList.Free;
end;

The 'magic' memory freeing applies to the fList POINTER, but not the object that you've created.

So, in general, you don't actually have to call the inherited destructor, but I can't really think of a reason why you might want to avoid it.


Why is it virtual? Because most of the time you destroy objects using 'Free' instead of 'Destroy', and quite often you destroy objects using a variable which is pointing to a base class. Both of these need a virtual mnethod.

The definition of 'Free' is roughly

procedure tObject.Free;
begin
  if ( Self <> nil )
    Self.Destroy;
end;

If the destructor wasn't virtual, that would only call tObject.Destroy whereas you want it to call txxx.Destroy - the bottom of the class structure.

Consider too:

tBaseClass = class(tObject)
...
destructor Destroy; override;

tClassOne = class( tBaseClass )
....
destructor Destroy; override;

tClassTwo = class( tBaseClass )
...
destructor Destroy; override;


then

var x,y : tBaseClass

x := tClassOne.Create;
y := tClassTwo.Create;

x.Destroy; (or x.Free;)
y.Destroy;

when you call x.Destroy you've a variable pointing to tBaseClass, but you want to have tClassTwo.Destroy called. Similar for y. Hence you want virtual destructors.


Hope that makes enough sense to be useful!

Andrew.
0
 
LVL 2

Author Comment

by:j42
ID: 8195177
Hi Andrew,

Since you did a lot of writing I have increased points :-)

> Why is it virtual? Because most of the time you destroy
> objects using 'Free' instead of 'Destroy', and quite
> often you destroy objects using a variable which is
> pointing to a base class. Both of these need a virtual
> mnethod.
Hooray, I've got it!

> The destructor is similar, in a way. Calling a
> destructor runs the code you've written,
> then 'magically' frees off the memory allocated for the
> object.
Sorry, I did not provide you with enough information. What I intended to ask was if it is possible to call the destructor without actually destroying the object - like calling the constructor without creating an object.



Thanks so far
J
0
 
LVL 12

Accepted Solution

by:
andrewjb earned 600 total points
ID: 8195236
Call the destructor without destroying the object?

No - you can't. The 'magic' memory freeing always happens.


Another thing:

If a constructor fails for some reason (e.g. not enough memory, or an exception is raised) then the destructor gets called. However, note that not everything might have been created yet.

e.g.

if your constructor contains

fList1 := tStringList.Create;
{Do something else}
fList2 := tStringList.Create;

and the {something else} causes an exception, then the destructor gets called, but only fList1 has been created

So, that's why you typically use 'Free' instead of destroy, in destructors...

destructor tMyClass.Destrot;
begin
  fList1.Free;
  fList2.Free;
  inherited;
end;

and you don't need to worry whether fList1 and 2 have actually been created yet. (All variables are initialised to 'nil', so you can be sure that fList2 is still 'nil'.

0
 
LVL 2

Author Comment

by:j42
ID: 8196681
Thanks a million!

> So, in general, you don't actually have to call the
> inherited destructor, but I can't really think of a reason
> why you might want to avoid it.
Just to satisfy curiosity...

0
 
LVL 12

Expert Comment

by:andrewjb
ID: 8196708
No probs!

Hey - and constructors need to be virtual if you're building components to go on a form (anything derived from TComponent or a child) because of the way Delphi creates them...

0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
Suggested Courses
Course of the Month14 days, 18 hours left to enroll

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question