Another Polymorphism question

T

tshad

I have the following set of classes that originally had all the classes
except for the DrawingObject class set to override. I understand how these
all work.

But when I changed the Circle class to new virtual it called Circle.Draw, it
called the original Draw from the Drawing Object. I assume this is because
I am not overriding the DrawingObjects Draw method.

But does this mean that the Circles method will not be called unless I have
another Class that inherits from the Circle class?
**********************************************88
using System;

public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}

public class Line : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}

public class Circle : DrawingObject
{
new virtual public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

public class Square : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}

public class DrawDemo
{
public static int Main( )
{
DrawingObject[] dObj = new DrawingObject[4];

dObj[0] = new Line();
dObj[1] = new Circle();
dObj[2] = new Square();
dObj[3] = new DrawingObject();

foreach (DrawingObject drawObj in dObj)
{
drawObj.Draw();
}
Console.Read();
return 0;
}
}
**********************************

Thanks,

Tom
 
T

tshad

tshad said:
I have the following set of classes that originally had all the classes
except for the DrawingObject class set to override. I understand how these
all work.

But when I changed the Circle class to new virtual it called Circle.Draw,
it called the original Draw from the Drawing Object. I assume this is
because I am not overriding the DrawingObjects Draw method.

But does this mean that the Circles method will not be called unless I
have another Class that inherits from the Circle class?
**********************************************88
using System;

public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}

public class Line : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}

public class Circle : DrawingObject
{
new virtual public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

public class Square : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}

public class DrawDemo
{
public static int Main( )
{
DrawingObject[] dObj = new DrawingObject[4];

dObj[0] = new Line();
dObj[1] = new Circle();
dObj[2] = new Square();
dObj[3] = new DrawingObject();

foreach (DrawingObject drawObj in dObj)
{
drawObj.Draw();
}
Console.Read();
return 0;
}
}
**********************************

That didn't work either.

When I made Square inherit from Circle, it ididn't call the "new virtual
method Draw" of Circle. It still went back to the original DrawingObjects
Draw.

So Circles Draw is never called.

Why is that?

Thanks,

Tom
 
P

Peter Morris

public class Circle : DrawingObject
{
new virtual public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

Why would you want it to be "new"? I presume this is a nonsense example
just to help you to understand it?

If so you would need

(meh as Circle).Draw();

In order to find the "new" Draw method. Otherwise it will use the
DrawingObject.Draw.
 
P

puzzlecracker

I am even more confused as to why you need "new" here to begin with.
From my understanding, "new" is only needed when you override a method
with a different signature, but the same name in the derived class.
Please correct if my understanding is invalid.

Thanks
 
R

Rudy Velthuis

puzzlecracker said:
I am even more confused as to why you need "new" here to begin with.
From my understanding, "new" is only needed when you override a method
with a different signature, but the same name in the derived class.

Actually, it can even be the same signature and same name again. New
simply hides the original method, i.e. using new in this context means
you do not want to override the method of the ancestor class, but want
to create a new method instead, which does not take part in the orginal
virtual call chain anymore. Since he uses "virtual", it will take part
in a new virtual call chain.

So calling Draw on a Circle assigned to an instance declared as
DrawingObject ought to output the line "I'm just a generic drawing
object.", and not "I'm a Circle". Overriding is done properly for Line
and Square.
 
T

tshad

Peter Duniho said:
I have the following set of classes that originally had all the classes
except for the DrawingObject class set to override. I understand how
these
all work.

But when I changed the Circle class to new virtual it called
Circle.Draw, it
called the original Draw from the Drawing Object. I assume this is
because
I am not overriding the DrawingObjects Draw method.

But does this mean that the Circles method will not be called unless I
have
another Class that inherits from the Circle class?

No. If you use a variable (or other expression) of type Circle to
reference the instance, you'll get the implementation in Circle. For
example:

((Circle)dObj[1]).Draw();

Should output:

I'm a Circle.

You really should not hide virtual methods though. It's a very bad idea.
I mean, hiding _any_ method is generally a very bad idea, but hiding
virtual methods is super-bad (and not in a good way).
I understand. I am just trying to get the concept.

What is confusing me is the times when virtual changes what gets called.

If change the program slightly to make Square inherit Circle (which inherits
DrawingObject) and do the following:

DrawingObject doa = new Square();
doa.Draw();

******************************************
using System;

public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}

public class Line : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}

public class Circle : DrawingObject
{
new virtual public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

public class Square : Circle
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}

public class DrawDemo
{
public static int Main( )
{

DrawingObject doa = new Square();
doa.Draw();

Console.Read();
return 0;
}
}
****************************************


I go to the DrawingObjects Draw method.

I would have thought I would have either gone to the Circles Draw method or
the Squares draw method.

If I take change the "new virtual" to override in the Circle class:

public class Circle : DrawingObject
{
override public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

Then doa.Draw() goes to the Squares method as it does if all the classes
were inheriting DrawingObject.

But if all classes were inherting the DrawingObject and I put the "new
virtual" in the Circles Draw method, it would still go to the Squares Draw()
method.

Why does putting virtual at Circle cause it to go all the way back to
DrawingObject?

Thanks,

Tom
 
R

Rudy Velthuis

Peter said:
That's pretty much the opposite of when you need "new". :)

Oops. Not what I meant actually. I meant if you write a method with the
same sig and name but do NOT want to override the existing virtual one,
i.e. you don't want the new method to be part of the (same) virtual
chain the previous one was part of.


--
Rudy Velthuis http://rvelthuis.de

"Sometimes when reading Goethe I have the paralyzing suspicion
that he is trying to be funny."
-- Guy Davenport
 
R

Rudy Velthuis

Peter said:
That's pretty much the opposite of when you need "new". :) If the
signature's different, it's a whole different method and no hiding is
needed.


Actually, if it's not the same signature (including name), there's no
point in using "new", and the compiler will generate a warning (since
you're telling it to hide a class member that's not there).

Assuming name is the same (different name and it doesn't matter) but
not the signature, wouldn't "new" suppress the warning, since by using
"new" you tell the compiler you want to reintroduce that name, i.e. you
are aware of the fact you are hiding a virtual method? I can't try
this, ATM.
 
R

Rudy Velthuis

Peter said:
That's what you wrote (that is, what you said you meant). The
comment from me you quoted above was in respect to the text quoted
above it, which was written by "puzzlecracker", not you. It just
happened it was easier to respond to both in a single post, since
you'd already quoted it. :)

Dammit! I should better remember what I say. <g>

Well, obviously Hejlsberg got this from Delphi, which has had the
reintroduce directive, with exactly the same purpose, for ages already.
 
R

Rudy Velthuis

Peter said:
Sorry, I might not have been clear. The warning happens when you use
"new" on a method that isn't actually hiding anything

Oh, Ok, makes sense.
 
T

tshad

Peter Morris said:
Why would you want it to be "new"? I presume this is a nonsense example
just to help you to understand it?

Yes.

Everyone is zeroing in the "new". I was adding in a virtual to break the
inheritance chain. You have to add the "new" if you do that.
If so you would need

(meh as Circle).Draw();

In order to find the "new" Draw method. Otherwise it will use the
DrawingObject.Draw.

The chain and the breaking of the chain is what is confusing.

If you have a chain:

a -> b -> c -> d -> e -> etc where each inherits from each other and each
(some method) overrides each other.

if I have an object that is of type "a" but is really "e" (my DrawObject doa
= Square())

If I leave it like this:

doa.Draw would actually call Square.Draw() and NOT DrawObject.Draw().

But if I stick a "virtual Draw" anywhere along this chain, doa.Draw would
call the method of the class BEFORE the virtual.

I think part of my problem was the example didn't have enough object for the
chain to show what my confusion was.

Here is another (in a long list of examples :) )

Obviously, we normally wouldn't do this. These objects would not normally
inherit from each other. As you said - just to get my head around it.

***********************************************************
using System;

public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}

public class Line : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}

public class Elipse : Line
{
public override void Draw()
{
Console.WriteLine("I'm an Elipse.");
}
}

public class Triangle : Elipse
{
public override void Draw()
{
Console.WriteLine("I'm a Triangle.");
}
}

public class Circle : Triangle
{
override public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

public class Square : Circle
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}

public class DrawDemo
{
public static int Main( )
{
DrawingObject[] dObj = new DrawingObject[4];

DrawingObject doa = new Square();
doa.Draw();

Square sq = new Square();
sq.Draw();

Console.Read();
return 0;
}
}
}

***********************************************************

In my example, each class inherits from the one before.

If I leave like this,

My doa.Draw(), I assume goes to the DrawObject.Draw is of TYPE DrawObject.
But since it is actually a Square, it goes up the chain until it either
finds a class with NO Draw method, Virtual Method (and then it stops and
will use the Class before it) or until it gets to the actual object which is
the Square. So in this case it stops at Square.Draw().

but if I stick a "virtual" on the method of any class (lets say the
triangle),

***********************************************************
using System;

public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}

public class Line : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}

public class Elipse : Line
{
public override void Draw()
{
Console.WriteLine("I'm an Elipse.");
}
}

public class Triangle : Elipse
{
public override void Draw()
{
Console.WriteLine("I'm a Triangle.");
}
}

public class Circle : Triangle
{
new virtual public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

public class Square : Circle
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}

public class DrawDemo
{
public static int Main( )
{
DrawingObject[] dObj = new DrawingObject[4];

DrawingObject doa = new Square();
doa.Draw();

Square sq = new Square();
sq.Draw();

Console.Read();
return 0;
}
}
}

***********************************************************

In this case, it would go to the "Type or Class" (DrawObject) and move up
the chain toward the actual object (Square) until it hit the Triangle class
and would execute the Elipse.Draw().

Is that about right?

Thanks,

Tom
 
T

tshad

Peter Duniho said:
If I take change the "new virtual" to override in the Circle class:

public class Circle : DrawingObject
{
override public void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

Then doa.Draw() goes to the Squares method as it does if all the classes
were inheriting DrawingObject.

Of course it does. Square.Draw() overrides Circle.Draw() which overrides
DrawingObject.Draw(). The most-derived override is the one that gets
called, as long as you haven't broken the chain of inheritance by hiding
with the "new" modifier.
I am not trying to be difficult here. Just am confused at why a couple of
things happen.

I understand that Square.Draw() overrides Circle.draw.

But I think I didn't have a good enough example to show what I was getting
at. I have another example (a better chain) in my response to Peter.

Is it "new" that breaks the chain or the "virtual"?

Thanks,

Tom
 
T

tshad

Peter Duniho said:
No one ever is. :) (Well, actually...for a very few people, that's
actually not true...but I'm sure it is true for you and most other people
around here).


Okay...well, we are here to try to help. Let's hope we can clear up the
confusion, whatever it is.


I will go look at your other example. But, I can tell you right now: it
is _always_ "new" that breaks the chain of virtual inheritance. That's
what it does when applied to virtual methods. You cannot even use
"virtual" without "new" if the base class already has a method of the same
name and signature (and of course if there is no such method, you can use
"virtual" without "new" and without breaking any chain of virtual
inheritance).
I'm sure that is true.

I know that if you put virtual without new and there is already a method
with that name it tells you are hiding it and are you sure you want to do
that and if so, put "new" there. So I assumed that new was only there to
say you really wanted to do it and virtual was the actual breaking of the
the chain.

Thanks,

Tom
 
P

Peter Morris

I am even more confused as to why you need "new" here to begin with.
From my understanding, "new" is only needed when you override a method
with a different signature, but the same name in the derived class.
<<

Different parameters == "overloading", and nothing to do with virtual / new
at all. You can always overload a method because the uniqueness of a method
is its name + parameters and not just its name so effectively two methods
with the same name but different parameters are two different methods
regardless of the fact that their names are the same.

When you create an instance of a class the method code is not created, only
its state is, the code is shared across all instances of that class (and
subclasses). To know which method to call there is a table of method
addresses, so when you call Draw() it looks up the address of
DrawingObject.Draw() and calls that. This can be affected in different ways

01: You override a virtual method.

In this case looking of DrawingObject.Draw() will find the address of the
"overridden" method and call that. If that overridden method calls
"base.Draw()" then that will look up the method address from its parent
class, and so on.

When you pass a descendant of DrawingObject to a method and that method
calls passedInstance.Draw() it will do exactly the same, because the
overridden method has replaced the address of DrawingObject.Draw in its
method address table.


02: You "new" a method, virtual or not.

In this case your Circle will have a new entry in the method table. Any
calls to Draw will use the lookup for entry for the new method rather than
the lookup entry for DrawingObject. If your "new" method calls base.Draw()
it will execute the method pointed to by the original entry.

However, when you pass this instance to a method expecting DrawingObject and
that method calls passedInstance.Draw it wants to draw a DrawingObject so it
looks up the method address of Draw() using the entry number in the method
table for DrawingObject (which let's say is position 1). In this case
DrawingObject.Draw would be called.


So to summarise:

[Method table for DrawingObject]
1: Draw { Points to DrawingObject.Draw}

[Method table for class that overrides the Draw method]
1: Draw {Points to OverriddenDrawingObject.Draw}

[Method table for class that "new"s the Draw method]
1: Draw {Points to DrawingObject.Draw} - but only the new class's methods
can call base.Draw()
2: Draw {Points to NewDrawingObject.Draw}

public class DrawingSurface
{
public void DrawShapes(
DrawingObject drawingObject,
DrawingObject overriddenDrawingObject,
NewDrawingObject newDrawingObject
DrawingObject newDrawingObject_PassedAsType_DrawingObject)
{
//This finds the method address in DrawingObject slot 1, no matter
what
//class the instance is
drawingObject.Draw();

//This also finds the method in DrawingObject slot 1, no matter what
the
//class instance is. This is because OverriddenDrawingObject
"overrides"
//the original, which means that it stores the new method address in
//the same method slot.
overriddenDrawingObject.Draw();

//Because we know this instance is at least a NewDrawingObject and
//NewDrawingObject creates a new method slot (using "new") we know
//not to look in slot 1, but in slot 2 instead
newDrawingObject.Draw();

//This one is actually a NewDrawingObject, but because this method
//wants a simple DrawingObject it means that we want to treat it
like
//a DrawingObject. In this case slot 1 is used, we don't use the
"new"
//slot because that would be treating it like a NewDrawingObject.
//If you wanted your new implementation to be used in this case you
//should override the method rather than using "new"
newDrawingObject_PassedAsType_DrawingObject.Draw();
}
}

Disclaimer: For those of you who will rip apart the accuracy of this, yes,
I know it is not *exactly* how classes are structured in memory but I think
it is a good way of explaining the logic of the behaviour rather than the
implementation.
 
R

Rudy Velthuis

Peter said:
In C#, methods are non-virtual by default. But in addition, they
decided to ensure that it's always explicit what relationship a
method has to its inherited and derived types. The "virtual" and
"override" keywords both do basically the same thing that the one
"virtual" keyword does in C++, but by using two different ones, the
compiler can tell when you're overriding on purpose versus trying to
hide a method (intentionally or not).

There have even been attempts to propose something like "override" to
C++ as well, by two people I know (they got their ideas from Delphi,
though). I must admit I didn't follow their efforts and how far they
got.

Using non-virtual methods by default, and the system with the
directives virtual, override and new where appropriate is IMO the best
of both worlds.
--
Rudy Velthuis http://rvelthuis.de

"The wit makes fun of other persons; the satirist makes fun of
the world; the humorist makes fun of himself."
-- James Thurber (1894-1961),
in Edward R. Murrow television interview
 
P

Peter Morris

Using non-virtual methods by default, and the system with the
directives virtual, override and new where appropriate is IMO the best
of both worlds.

I assume it removes a level of indirection that is a few cycles slower.
 
T

tshad

Peter Duniho said:
[...]
Well, as I said in my other reply, "new" is what breaks the chain of
virtual inheritance.
Agreed.
The chain and the breaking of the chain is what is confusing.

I hate to break it to you, but in reality, there's not even a chain as
you're visualizing it. Inasmuch as your understanding of the way virtual
methods work is correct (and I think there are still flaws :) ), it's only
correct in a conceptual sense. The underlying implementation doesn't
involve any "chaining" at all.

And that was really what I am doing. I understand that the underlying
implementation is different.
But I assume that when a project if built, it would have to follow the chain
to be able to set up the pointers and vector tables you mention.
Not that it's not useful for you to learn how all this works, or even to
use the concept of chaining, but you should be careful to make sure you
understand this is strictly a high-level conceptual thing, describing the
OOP relationship of your classes, rather than having anything to do with
how the code is actually executing.

I do understand that it is a high-level concept, which is what I am trying
to do to understand it better. Then I will get into the pointers (which are
not really necessary to understand to deal with the classes).

One of the responses was correct but was confusing because I didn't have a
real chain set up. I had the 1st Class that followed the DrawObject as
"new". So the person correctly said that when that was set to new then
doa.Draw() would go to the DrawObject.Draw method. The problem is that
didn't help me understand how the chain worked. Once the "new" was added
down the chain, then it made more sense. It went to the DrawObject.Draw and
will move up the chain until you find either another "new or the actual
class (in my test case - Square.Draw()). I thought that if you had a class
in the chain that didn't have the method at all, it would keep going. I
thought not having that method would stop the chain as well as "new" but
when I took the Draw() method out of Triangle completely (so that there was
no "new" or override in this class or in the chain at all) it went all the
way to Square.Draw(). So I was wrong there. Only the "new" would stop the
chain unless ALL the classes up to Square had no Draw() method.
That said...on with the discussion:


Warning: that's a self-contradictory statement. I know what you mean, but
the _object_ is _always_ just whatever type it is. You can reference that
object with variables of any type that object inherits or implements, but
the object itself always _is_ whatever type it "really is".
So is:
DrawObject doa = new Square()

a DrawObject or a Square (DrawObject being the "type" - what would you call
the Square here)?
I think you should stick to letters for your type names. Using actual
geometry terms just confuses the issue (well, at least for me anyway),
because it's very difficult to turn off the part of the brain that
interprets those terms.
I only did that because that was the original test program I was using. And
at that point, each class didn't inherit from each other. They all
inherited from DrawObject. But I was trying different things to see what
would happen with the test I had.

When I did the last one with the letters, I thought about changning the
program to use the letters but thought THAT might be confusing since we have
been referring to geometric figures throughout this thread.
Using your original chain, we can rephrase the statement as:

if a variable "a" references an object of type E, "a.Draw()" would
actually call E.Draw() and not A.Draw();

If you say "a" references an object of type E, are you saying:

A a = new E();

or

E a = new A();

Just trying to get the order right here.
If you stick a "new virtual" Draw() method anywhere along this chain,
"a.Draw()" would call whatever Draw() method is the most-derived override
in the chain of inheritance up to but not including the class where you
stuck the "new virtual" Draw(). This may or may not be in the immediate
base class of the class where you stuck a "new virtual" Draw() method.
By most-derived override, you also mean up to the object whichever comes
first.

For example, if:

A a = new E()
a.Draw()

It would go from A towards e until it hits a wall ("new").
I think part of my problem was the example didn't have enough object for
the
chain to show what my confusion was.

[...]
If I leave like this,

My doa.Draw(), I assume goes to the DrawObject.Draw is of TYPE
DrawObject.

I don't understand that statement. It's not a grammatically parseable
sentence.

Maybe not but what I meant to say (what I was asking above), I assume that
doa is of TYPE DrawObject and not of TYPE Square when I say:

DrawObject doa = new Square();
I realize that now.

But if I take out the "finds a class NO Draw Method" out of the statement,
than I assume this correct - in a high-level concept.
Not exactly. Finding a class "with NO Draw method" doesn't affect which
method is called at all. For example:

class A
{
virtual void Method1() { }
}

class B : A
{
}

class C : B
{
override void Method1() { }
}

then:

A a = new C();

a.Method1();

This will call C.Method1(), not A.Method1().

I didn't realize that override would extend over a directly inherited class
(B in this case) to override A's Method1. I do now, though.
but if I stick a "virtual" on the method of any class (lets say the
triangle),

It's not the "virtual". It's the "new". :)
[...]
In this case, it would go to the "Type or Class" (DrawObject) and move up
the chain toward the actual object (Square) until it hit the Triangle
class
and would execute the Elipse.Draw().

For what it's worth, you're off by one on your types. Your example shows
a "new virtual" method in the Circle class, not the Triangle class.

You're right. Missed that.
But, as far as your description goes, yes...once you've got that "new
virtual" in a class, then you've got a whole new virtual method there, and
because it has the same name as the base virtual method, it hides it from
that type on in the inheritance chain.

I assume that by base virtual method, you don't necessarily mean the
immediately previous class but the first class going backwards down the
chain until the 1st method is found whether it is a "new" method or
"override" method. This was something I wasn't clear about, as well until I
tried it. I had assumed the "base" meant the Class that this class was
inheriting from directly.

So using your example:

class A
{
virtual void Method1() { }
}

class B : A
{
}

class C : B
{
base.Method1();
override void Method1() { }
}

Here base.Method1() would refer to A.Method1(), even if there was a class
before "A" that had a Method1().
So, if you have an object that's of that type or later in the inheritance
chain, then which method you get depends on the type of the variable used
to call the method, because different types see different methods. Types
from the very base class all the way up to the class just before the one
where you hid the base method will see the base method. Types from the
method where you hid the base method on will see the new method.


I have no idea if this will help you understand or not (it might just
confuse you more, and if so I apologize...you can ignore this last part of
my post if you like :) ), but I'll give you a little bit of the
implementation details of virtual methods. They are commonly implemented
in various languages using what's known as a "v-table". A v-table is
really just an array of function pointers.

When you declare a virtual method, that reserves a new slot (array
element) in the v-table for that method and stores a reference to that
class's implementation of the method in the slot. When you call a virtual
method, rather than calling the method directly, the compiler generates
code that will use the method reference found in the slot that goes with
the method name and signature. When a sub-class overrides a virtual
method, rather than creating a new slot, it just replaces the base class
reference with its own reference of its implementation, so that its method
is the one that gets called instead.

Which is what I said above (I think). During the build it would follow all
the chains and sets up the pointers at that points. I realize that it would
be more complicated than that, especially for objects set up dynamically:
objects set up in arrays at runtime, for instance.
Very important: for a given type, there is a one-to-one correspondence
between the method name and signature, and the v-table entry for that
method name and signature.

No matter how far down the inheritance chain you go, as long as no one
hides the virtual method, a new slot for the method isn't ever added to
the v-table. Each class just provides its own reference for the one slot
that was reserved and each class always uses that one slot when calling
the virtual method.

Now, when you hide a virtual method, that essentially creates a whole new
method, which means you do get another slot in the v-table. The thing is,
any time you execute code using the type that hid the method or a type
that inherits that type, you've _hidden_ the previous method. The slot in
the v-table that corresponds to the method that was hidden is,
well...hidden. No code, using those types, will ever be able to execute
that method, because the name and signature that goes with that method
refers instead to the new slot.

On the other hand, any time you execute code using a type earlier in the
inheritance chain than the type that hid the method, that code doesn't
know anything about the new method. It only knows about the original
virtual method, and so that code will always use the original v-table
entry for the method.

In other words, hiding a virtual method results in two different v-table
entries for the given method name and signature, and which entry is used
depends on the type of the _variable_ used to call the method (because
that's all the compiler knows at the point where it's generating code for
the call). If you use the base types, you get the original v-table
entry. If you use the type that hid the original method, or a type that
inherits that type, you get the new v-table entry.

"...and never the 'twain shall meet". :)

Finally, note that in the above I talk about just one hiding of a method,
but of course any class can hide any inherited method, and for virtual
methods, every time the method is hidden, that forces a new v-table entry
to be created. For a given method name and signature, any given type can
only ever see one implementation of that method name and signature at a
time, and so which implementation is called depends on the type of the
variable used to call it.

Good information.

Would be nice if there were better papers on this that show the v-tables and
how they work with inheritance with good diagrams and compared to the
high-level concepts to get a better idea on how it works. Typically, it is
a couple of classes with a "new" in the middle class and then a comment that
the chain is now broken. But without a chain with 6 or 7 "links", you
really don't see what is happening.

I think I have a much better handle on this, now.

I appreciate the explanations.

Thanks,

Tom
 
T

tshad

Peter Duniho said:
[...]
So is:
DrawObject doa = new Square()

a DrawObject or a Square (DrawObject being the "type" - what would you
call
the Square here)?

Neither. It's a line of C# code that declares a variable "doa" and
initializes it as a new instance of Square.
Right, I meant to ask if doa is a DrawObject "type", what would you call
Square here (which you answer below).
The variable "doa" has the type DrawObject, but the object created has the
type Square.

So doa, which is really just a pointer, is a pointer of type DrawObject.
The object created is of type Square. I am them pointing doa at the object
Square. So I have 2 "types" here. I get confused as to why this would be
done. Yet it is done either the way I did it or passed as the base object
or casting it as DrawObject:

public Method(DrawObject j)
{
...
j.Draw();
}
....
public Main()
{
Square s = new Square();
Method(s);
s.Draw();
}

In this case, s.Draw() would get the Squares Draw() method.

But j.Draw() would get the Draw() it finds following the chain from
DrawObject.Draw until it either hits the wall ("new") or finds the
Square.Draw().

I am confused as to why we would do this.
[...]
But, as far as your description goes, yes...once you've got that "new
virtual" in a class, then you've got a whole new virtual method there,
and
because it has the same name as the base virtual method, it hides it
from
that type on in the inheritance chain.

I assume that by base virtual method, you don't necessarily mean the
immediately previous class but the first class going backwards down the
chain until the 1st method is found whether it is a "new" method or
"override" method. This was something I wasn't clear about, as well
until I
tried it. I had assumed the "base" meant the Class that this class was
inheriting from directly.

See above. There is a way to interpret the OOP constructs in which "base"
always does refer to the immediate base class, while still accepting that
implementation found in earlier base classes can still be overridden,
hidden, etc. IMHO, rather than treating each class as a separate entity
unto itself, if you consider any given class as a union of itself and
every class it inherits, then some of this stuff works more naturally.

I agree.

but you still need to know the order of inheritance, I would think because,
as in the following example, you would need to know the order of inheritance
to know which Method1() would be called. Here E calls base.Method1() and
would get to C.Method1() not B.Method1() or A.Method1() (I believe).
Without taking each entity separately, how would you know?

class A
{
virtual void Method1() { }
}

class B : A
{
virtual void Method1() { }
}

class C : B
{
override void Method1() { }
}

class D : C
{
}


class E : D
{
override void Method1()
{
base.Method1();
}
}
[...]
Which is what I said above (I think). During the build it would follow
all
the chains and sets up the pointers at that points. I realize that it
would
be more complicated than that, especially for objects set up dynamically:
objects set up in arrays at runtime, for instance.

It doesn't matter where the object is referenced. It's always the same.
And no, it doesn't happen at compile time, except inasmuch as at compile
time, an instruction to create a new instance is emitted. It's part of
the construction of the object, where the compiler-provided implementation
in the constructor initializes the v-table.

The only "follow all the chains" that happens, happens when the compiler
actually compiles the type. That's the only time it has to worry about
it. By compiling the type correctly (including constructors,
initialization code, etc.), the rest of the behavior just happens
naturally for any code that uses the type, without the compiler having to
do a search of the inheritance tree every time it sees the type being
used.
Right.

That I understand and was what I was saying. At build time it would follow
all the paths using the various things involved in a class. Not at runtime.

Thanks,

Tom
 
B

Ben Voigt [C++ MVP]

class (in my test case - Square.Draw()). I thought that if you had a
class in the chain that didn't have the method at all, it would keep
going. I thought not having that method would stop the chain as well as
"new" but when I took the Draw() method out of Triangle completely (so
that there was no "new" or override in this class or in the chain at all)
it went all the way to Square.Draw(). So I was wrong there. Only the
"new" would stop the chain unless ALL the classes up to Square had no
Draw() method.

But the class which you think doesn't have a Draw method, actually does.
You didn't define one, so it inherited the version in its base class (which
might have been defined in the base class or inherited from yet another
base).
 
T

tshad

Peter Duniho said:
[...]
So doa, which is really just a pointer, is a pointer of type DrawObject.
The object created is of type Square. I am them pointing doa at the
object
Square. So I have 2 "types" here. I get confused as to why this would
be
done.

This is one of the primary features of OOP. The reason it would be done
is that very often, code that uses an object doesn't care what the actual
type of the object is, but rather just some subset of its implemented
API. Used in conjunction with virtual methods, it's a very powerful way
to isolate functionality and provide for a flexible way to implement
things.

For example, if you want to write some data out as text somewhere, but
have no other need to operate on objects, then the _only_ thing you need
is a way, given an object, to return some text that represents that
object. This is exactly what Object.ToString() does. The default
implementation is usually not very useful (just tells you the type), but
presumably you would override that virtual method with something more
useful.
This I understand.
Without virtual methods, to get different results from different objects,
you have to know the full type of the object and call that specific method
using that type. But, with virtual methods, that allows code to treat the
object using the simplest, least-derived type in that object's inheritance
hierarchy that still supports the functionality needed. In the case of
code that needs the ToString() method, this least-derived type is the base
type for every single other type -- Object -- and code can use that
without knowing _anything_ else about the type of the object.
But you wouldn't get the least derived method (as in the case, of the
ToString() method) but the most derived method, right?

if A was the base class and E was the object we are using:

A a = new E();
a.ToString();

You would get the most derived ToString() method starting from A until it
hit either a "new" or the E object. Correct?

If this is the case, all that a does is give you acces to less properties
and methods and you can't even be sure which methods will actually be used
unless you follow the chain yourself? So what does it buy you?
Code that restricts what it knows, deals with, has to take care of, etc.
is simple code, and simple code is easier to understand and maintain.


That depends on the declaration of the types. The only reason you can say
which method is used is because you know that you've explicitly created a
Square() instance. But the code used to call the method -- "s.Draw()" --
doesn't know that any more than the code in the Method() method does.
Right, but I am using the previous example where I obviously know what
Square is.
That depends on what's in Square, and is only true because we know the
type is Square. Sure, if Square has an implementation of Draw(), that's
the one that would be used, assuming no other class hid the original
virtual method.
Which is what I am saying. If you use the base class, you have no idea
which version of any method will get called if there is a long chain of
classes.

If we used the A ->E example, where A is the base class and we did as I
mentioned above:

a.ToString() -> I might get Cs' implementation.

If I did:

a.MethodSomething() -> I might get Bs' implementation of MethodSomething

If I did:

a.MethodSomethingElse() -> I might get Ds' implementation of
MethodSomethingElse().
I am confused as to why we would do this.

Well, I think this is one of the reasons the example you're using is
poor. You have created a class hierarchy that would never actually be
used, because Circles are not Squares are not Triangles. The hieararchy I
suggested wouldn't illustrate a practical use for virtual methods, but at
least it's not self-contradictory.

The short answer, as I've alluded to above, is that it's often useful to
be able to use an object without knowing the specific implementation.
Your own DrawingObject example would be suitable, except you've got
contradictory shapes inheriting from each other. If you just had a bunch
of different shapes all inheriting from DrawingObject, it would be simple
enough to point out that you don't need to know what shape an object is in
order to get it to draw itself; you just need to know it inherits
DrawingObject, and code that wants to draw one only has to deal with
DrawingObjects.

Imagine how cluttered the code would get if the code that drew objects had
to special-case each possible type of object you might draw.

For a longer answer, you really should read some better resources on OOP
programming. Find a good textbook, or perhaps read some of the articles
on Wikipedia (which are not what I'd call excellent, but they are at least
much more thorough than anything you're going to get here). I don't think
a newsgroup is really the best place to get a thorough education on
programming techniques and concepts. If the "brief" discussion that's
been provided so far doesn't explain it for you, then you need a much more
detailed and introductory reference than can be provided here.
[...]
See above. There is a way to interpret the OOP constructs in which
"base"
always does refer to the immediate base class, while still accepting
that
implementation found in earlier base classes can still be overridden,
hidden, etc. IMHO, rather than treating each class as a separate entity
unto itself, if you consider any given class as a union of itself and
every class it inherits, then some of this stuff works more naturally.

I agree.

but you still need to know the order of inheritance, I would think
because,
as in the following example, you would need to know the order of
inheritance
to know which Method1() would be called.

The whole point of using the OOP techniques is that you don't need to know
which Method1() would be called. You write the code with the assumption
of the base class and nothing else. Then sub-classes define their own
behavior, and things "just work".
Here E calls base.Method1() and
would get to C.Method1() not B.Method1() or A.Method1() (I believe).
Without taking each entity separately, how would you know?

Your code example doesn't compile. In class B, did you mean "override"
instead of "virtual", or did you mean "new virtual" instead of "virtual"?
Not that it really matters much, but you really ought to be posting valid
code examples. It's difficult to make comments on the invalid ones,
because there's no way to know for sure what you meant.
I meant it to be override.

I agree. And I understand the basic OOP of inheriting be books typically go
into the different variants or give you enough classes to the path patterns
and what happens when you are doing various assignments to baser classes of
an object. As I mentioned before, when something said that a.Method1()
(where A was the base class) would go to the a.Method1() - this was correct
but not entirely correct to understand what was really happening as far as
following the paths to find the correct method. That was what caused these
questions.

As for "how would you know": you don't need to know.

The only reason a sub-class would call the "base" implementation of a
method is because of reasons unrelated to _which_ method gets called. In
particular, when overriding a method, you need to decide whether the base
functionality is needed or not. Quite often it's not, but when it is, you
call the "base" implementation as a way of adding to that implementation.
And when you do that, you don't care if it was implemented one class
before, two classes before, or a dozen classes before (though one hopes
the class hierarchy doesn't go that deep :) ).

Even the compiler only needs to know the order and nature of inheritance
only at a specific moment during compilation. Once it's compiled the
type, the type itself represents everything the compiler needs to know
later when compiling code that uses the type.
[...]
The only "follow all the chains" that happens, happens when the compiler
actually compiles the type. That's the only time it has to worry about
it. By compiling the type correctly (including constructors,
initialization code, etc.), the rest of the behavior just happens
naturally for any code that uses the type, without the compiler having
to
do a search of the inheritance tree every time it sees the type being
used.
Right.

That I understand and was what I was saying. At build time it would
follow
all the paths using the various things involved in a class. Not at
runtime.

It's more than that though. It's not even during most of the build time
that it "would follow all the paths". Most of the time the compiler
encounters a type, there's no need to follow the type's inheritance
chain. The compiler does that once, when it's compiling the actual type,
and then that sets all the necessary information up for later use.
Got that.

Thanks,

Tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top