Do *this* pointer breaks overriding implementation?

G

Guest

Hi fellows,

According to the C# language specification (10.5.3), Every virtual method has a "most derived implementation" determined by a 3-step rule. If I invoke the virtual method from a normal variable, everything is ok. However if I call it inside a non-virtual method from the base class, that use's the *this*pointer to actually invoke the virtual method, then those rules doesn't seems to be respected. In fact, the behavior the code below (ilustrating the problem) induces me to belive that the *this* pointer is always resolved as compile-time type, when it should be run-time type (otherwise how could it access the the correct properties in polimorphic calls).

What am I missing here?


----
using System;

class A
{
public void G(){this.F();}
public virtual void F(){Console.WriteLine("A.F");}
}
class B:A
{
public virtual void F(){Console.WriteLine("B.F");}
}
class C:B
{
public virtual void F(){Console.WriteLine("C.F");}
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
C t = new C();
A a = t;
B b = t;
C c = t;
// the first tree calls are ok with the C# language
// specification for "most derived implementation" rule (10.5.3 Virtual methods)
a.F();
b.F();
c.F();
// The use of *this* pointer inside the G function
//breaks the most derived implementation rule.
a.G();
b.G();
c.G();
}
}
 
M

Mattias Sjögren

Eric,
According to the C# language specification (10.5.3), Every virtual method has a "most derived implementation" determined by a 3-step rule. If I invoke the virtual method from a normal variable, everything is ok. However if I call it inside a non-virtual method from the base class, that use's the *this*pointer to actually invoke the virtual method, then those rules doesn't seems to be respected. In fact, the behavior the code below (ilustrating the problem) induces me to belive that the *this* pointer is always resolved as compile-time type, when it should be run-time type (otherwise how could it access the the correct properties in polimorphic calls).

What am I missing here?

It's not the use of "this" that breaks polymorphism, it's the lack of
the override keyword on the derived implementations. You should get
CS0114 warnings when you compile the code informing you about this. To
get the behavior you want, change

public virtual void F(){Console.WriteLine("B.F");}

to

public override void F(){Console.WriteLine("B.F");}

and do the same in class C.



Mattias
 
G

Guest

Hi Mattias

Thanks for the reply, but I'm still lost. If I use the override on descendent class (for example, if I override the F method in B class), then when I try to invoke a typecast on a variable (the first 3 calls of the code. ie: a.F(), b.F()) the code will always execute the B.F() method, and descendent classes will lost the ability to "behave" as A class. I'm not very expericend with OOP (and for that, I might be saying a foolish here :) ) but isn't this "behave as" the polimorphic behavior

Also, the 10.5.3 Virtual methods C# language states:
"The most derived implementation of a virtual method M with respect to a class R is determined as follows:

- If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.
- Otherwise, if R contains an override of M, then this is the most derived implementation of M.
- Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to the direct base class of R.


If I use the "new virtual" keywords, I keep the polimorphic behavior on the first 3 calls of my code, but 3 subsequent calls of G() all resolve to A.F(). In other words

class A
public void G(){this.F();
public virtual void F(){Console.WriteLine("A.F");

class B:A{ new public virtual void F(){Console.WriteLine("B.F");}
class C:B{ new public virtual void F(){Console.WriteLine("C.F");}

when I call

C c = new C()
A a = c
a.G()

the compiler should enter A.G, evalueate this.F(), found that F is virtual and the runtime type of the class is C (this = C) and then since C.F has the virual keyword, shouldn't it be resolved as the most derived method and takes place

Is it possible (and if so, how) to make the code below produces the following output
A.
B.
C.
A.
B.
C.


using System

class

public void G(){F();
public virtual void F(){Console.WriteLine("A.F");

class B:A { new public virtual void F(){Console.WriteLine("B.F");}
class C:B { new public virtual void F(){Console.WriteLine("C.F");}
class Class

[STAThread
static void Main(string[] args

C t = new C()
A a = t
B b = t
C c = t
// the first tree calls are ok with the C# language
// specification for "most derived implementation" rule (10.5.3 Virtual methods
a.F()
b.F()
c.F()
// The use of *this* pointer inside the G function
// breaks the most derived implementation rule
a.G();
b.G();
c.G();



Thanks again for the help. Cheers

Eric
 
M

Mattias Sjögren

Eric,
If I use the override on descendent class (for example, if I override the F method in B class),
then when I try to invoke a typecast on a variable (the first 3 calls of the code. ie: a.F(),
b.F()) the code will always execute the B.F() method,

Right, if B.F overrides the virtual A.F, and B has the most derived
implementation of the method, B.F will run. That's the polymorphic
behavior you want with using virtual methods.

and descendent classes will lost the ability to "behave" as A class.

Not sure what you mean there. You should be able to use an instance of
B wherever an instance of A is required.

the compiler should enter A.G, evalueate this.F(), found that F is virtual and the runtime type of the class
is C (this = C) and then since C.F has the virual keyword, shouldn't it be resolved as the most derived
method and takes place?

No, using "new" is a way to explicitly say that you don't want C.F to
override A.F. C.F is a whole new method that is unrelated to A.F, they
just happen to have the same name.

So the most derived version of F that's called from A.G is A.F itself,
since B.F is a new method, not overriding A.F.

Is it possible (and if so, how) to make the code below produces the following output?
A.F
B.F
C.F
A.F
B.F
C.F

If you add

public new void G(){F();}

to B and C.



Mattias
 

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