Inheritance - Accessing two levels above mine - Now with virtual+override

B

Bill

Hi again,

Ok, so it looks like I can access an ancestor member that is two
levels above mine, if that ancestor has been hidden by means of "new".
But what if it has been overriden with "override"?

How can I access C1.fb() from inside C3.fb()?
Is it possible?

Thanks again,
Bill


// ----------------------------
namespace N0
{
public class C1
{
public int dbg_cnt=0;

public void fa()
{
Debug.Print("{0} - C1.fa()",dbg_cnt++);
}
public virtual void fb()
{
Debug.Print("{0} - C1.fb()",dbg_cnt++);
}
}

public class C2 : C1
{
new public void fa()
{
Debug.Print("{0} - C2.fa()",dbg_cnt++);
}
public override void fb()
{
Debug.Print("{0} - C2.fb()",dbg_cnt++);
}
}

public class C3 : C2
{
new public void fa()
{
Debug.Print("{0} - C3.fa()",dbg_cnt++);
((C1)this).fa(); // Does access C1.fa(). OK.
}
public override void fb()
{
Debug.Print("{0} - C3.fb()",dbg_cnt++);
// How to access C1.fb() from here?
//((C1)this).fb(); // Recursive. Infinite loop! Even though I
up cast it to C1, the override makes it point to C3.fb() (i.e., be
recursive).
//base.fb(); // This accesses C2.fb(), but I cannot access
C1.fb().
}
}
}
 
A

Arne Vajhøj

Bill said:
Ok, so it looks like I can access an ancestor member that is two
levels above mine, if that ancestor has been hidden by means of "new".
But what if it has been overriden with "override"?

How can I access C1.fb() from inside C3.fb()?
Is it possible?

No.

virtual/overridden methods are tied to the instance,
so you can not cast your way out of it.

And I don't think base.base.fb() will work.

Arne
 
B

Bill

No.

virtual/overridden methods are tied to the instance,
so you can not cast your way out of it.

Hmmm... I don't get it.
The code for a member method is not repeated for every instance (only
the space for member fields). I have an instance of C3 in my hands. If
the code for C2.fb() is tied to that instance (and indeed is, through
base), why is the code for C1.fb() not tied also to that instance??
Both were declared public.

I thought that override implied that "if you don't use a fully
qualified name, you'll be automatically linked to the most-specific
implementation of the member methods with that name." However, it
looks like it actually implies that "even if you use a fully qualified
name, you won't be able to access the least-specific implementation
(if it is two levels above yours)".
And I don't think base.base.fb() will work.

Right. It doesn't work. I tried it.

Thanks
 
A

Anthony Jones

Bill said:
Hmmm... I don't get it.
The code for a member method is not repeated for every instance (only
the space for member fields). I have an instance of C3 in my hands. If
the code for C2.fb() is tied to that instance (and indeed is, through
base), why is the code for C1.fb() not tied also to that instance??
Both were declared public.

I thought that override implied that "if you don't use a fully
qualified name, you'll be automatically linked to the most-specific
implementation of the member methods with that name." However, it
looks like it actually implies that "even if you use a fully qualified
name, you won't be able to access the least-specific implementation
(if it is two levels above yours)".

override means replace any implementation of a specfic member with an
alternative implementation.

C2 x = new C3();

x has the type of C2 but is refering to an instance of C3. If C3 overrides
a method of C2 then even when call the method using a variable of type C2
you will get the C3 implementation of that method.

This is very important concept that makes OO in C# (and pretty much all
other OO languages) work.

Perhaps it may be worth reviewing the basic guides to the language in the
documentation.

It also should be red flag to you that 1) you don't know the language well
enough and 2) what you are trying to do is an unsafe approach.

It sounds to me that your base class needs some protected abstract methods
that the derivatives will implement and the derivatives should not be
overriding the main public method. It depends on the design, but the design
needs to be built on sound OO principles which you do not yet have a proper
grasp of.
 
B

Bill

override means replace any implementation of a specfic member with an
alternative implementation.

No. You don't replace it. If you were really replacing the overriden
implementation, you would be getting rid of it, and you wouldn't be
able to access it any more. But you can. At least, the one-level-above
ancestor (with "base"). You didn't get my point.
C2 x = new C3();

x has the type of C2 but is refering to an instance of C3. If C3 overrides
a method of C2 then even when call the method using a variable of type C2
you will get the C3 implementation of that method.

This is very important concept that makes OO in C# (and pretty much all
other OO languages) work.

Perhaps it may be worth reviewing the basic guides to the language in the
documentation.

It also should be red flag to you that 1) you don't know the language well
enough and 2) what you are trying to do is an unsafe approach.

I agree that I don't know the language well enough. That's why I'm
asking. However, to the extent of what you wrote, I know it. I know
that if you call x.fb() you will execute C3.fb(), being x of type C2.
Events in custom controls wouldn't work if things were not that way. I
understand what you wrote, but I'm almost convinced that you didn't
get my point. Tell me: why is it safe to access the implementation
that is one level above (with "base"), but unsafe to access the
implementations that are two or more levels above? Any good answer for
this?

Thanks.
 
A

Anthony Jones

Bill said:
No. You don't replace it. If you were really replacing the overriden
implementation, you would be getting rid of it, and you wouldn't be
able to access it any more. But you can. At least, the one-level-above
ancestor (with "base"). You didn't get my point.

I think I do now. ;)
I agree that I don't know the language well enough. That's why I'm
asking. However, to the extent of what you wrote, I know it. I know
that if you call x.fb() you will execute C3.fb(), being x of type C2.
Events in custom controls wouldn't work if things were not that way. I
understand what you wrote, but I'm almost convinced that you didn't
get my point. Tell me: why is it safe to access the implementation
that is one level above (with "base"), but unsafe to access the
implementations that are two or more levels above? Any good answer for
this?

My apologies, my response did not show proper respect.

Now with that said and assuming you do know your OO apples and oranges the
following is going to sound like teaching grandma to suck eggs.

To answer your question simply:-

One the main precepts on which OO is built is encapsulation. What you are
trying to do breaks encapsulation.

More verbose:-

Given a class you can instance that class and use the members it exposes.
How it does what it does is its own business. Its important to realise that
a class that inherits from another class is still just another form of
consumer. The derived class should not know or care how the class from
which it inherits does its stuff.

A base class may allow some of its operation to be overriden by explicitly
stating a member is virtual. It can also explicitly choose to provide extra
services to inheritors that it wouldn't to other types of consumer via
protected members. Note the common feature here is that the base class
chooses for itself what it will allow an inheritor to do, an inheritor can
not interfere with operations that the base class hasn't granted access to.

Given:-

class A { public string virtual X {get; } }
class B : A { public string override X {get; } }
class C : B { public string override X {get; } }
class D : C { public string override X {get; } }

Class C can call base.X because it _is_ the consumer of the its base class B
and it has the perfect right to choose to skip around its own (or
derivatives D) implementation of X. However C is _not_ the consumer of A, B
is the consumer of A. C therefore does not have the authority to circumvent
Bs implementation of X, C can not know Bs reasons for overriding X as it
knows its own reasons for overriding X.
 
A

Arne Vajhøj

Bill said:
Hmmm... I don't get it.
The code for a member method is not repeated for every instance (only
the space for member fields). I have an instance of C3 in my hands. If
the code for C2.fb() is tied to that instance (and indeed is, through
base), why is the code for C1.fb() not tied also to that instance??
Both were declared public.

I thought that override implied that "if you don't use a fully
qualified name, you'll be automatically linked to the most-specific
implementation of the member methods with that name." However, it
looks like it actually implies that "even if you use a fully qualified
name, you won't be able to access the least-specific implementation
(if it is two levels above yours)".

Maybe it is easier to understand if we look at a typical
implementation of virtual.

The code for C1.fb, C2.fb and C3.fb are indeed separate. And
the code is not duplicated per instance.

But each instance contains a pointer to fb.

So when you do:

C1 o = new C3();
o.fb();

then that pointer points to C3.fb and even though the call
looks like calling C1.fb, the the pointer is used and C3.fb
is called.

This behavior is a very important part of OO and polymorphism.

And this is the reason that you can not use cast to what you want.
No matter if you cast to C1 or C2, then the pointer will still
be used.

Only way is special syntax. And there is only special syntax
for one level up.

Arne
 
B

Bill

To answer your question simply:-

One the main precepts on which OO is built is encapsulation. What you are
trying to do breaks encapsulation.

You know what? I know it. I do know that what I was trying to do is
not elegant. My main doubt is not whether that is elegant or not. In
this thread I asked whether that is _possible_ (and the answer seems
to be NO), and in another thread I asked whether someone can think of
a more elegant way of solving my problem. My main problem is "how can
I implement the 'partitioning' that I have in mind, and that makes
sense at least for me, in an elegant way?" Is there a solution that is
both elegant and that does not make me to repeat (copy & paste) code
logic?

Plot3.Init() needs to execute 3 sets of things: {A, B and C}
A = exactly what Plot1.Init() does (initialize Direct3D).
B = what Plot2.Init() does (initialize the cells), but referring to
Cell3 cells, not Cell2 cells.
C = added code, specific for level 3.

I have (at least) two options:
------------
Option 1 (elegant, but not code efficient):

Copy the code from Plot1.Init(), paste it into Plot3.Init().
Copy also the code from Plot2.Init(), paste it into Plot3.Init().
Remove the part of Plot2.Init() that called again to Plot1.Init()
(through base.Init()). Change the "...=new Cell2[..,..]" to "...=new
Cell3[..,..]".
Write the new code specific to Plot3.Init().
------------
Option 2 (not elegant, but more code efficient):

At least, do not copy and paste the code from Plot1.Init(). Execute it
from Plot3.Init(). That's why I made the question in this thread.
------------


Ok, don't worry. It looks clear that I have to change what I called my
'partitioning'.

More verbose:-

Given a class you can instance that class and use the members it exposes.
How it does what it does is its own business. Its important to realise that
a class that inherits from another class is still just another form of
consumer. The derived class should not know or care how the class from
which it inherits does its stuff.

I agree.
A base class may allow some of its operation to be overriden by explicitly
stating a member is virtual. It can also explicitly choose to provide extra
services to inheritors that it wouldn't to other types of consumer via
protected members. Note the common feature here is that the base class
chooses for itself what it will allow an inheritor to do, an inheritor can
not interfere with operations that the base class hasn't granted access to.

I agree.
Given:-

class A { public string virtual X {get; } }
class B : A { public string override X {get; } }
class C : B { public string override X {get; } }
class D : C { public string override X {get; } }

Class C can call base.X because it _is_ the consumer of the its base class B
and it has the perfect right to choose to skip around its own (or
derivatives D) implementation of X. However C is _not_ the consumer of A, B
is the consumer of A. C therefore does not have the authority to circumvent
Bs implementation of X, C can not know Bs reasons for overriding X as it
knows its own reasons for overriding X.

This paragraph is very good. Very clarifying. Ok, that explains why
the language allows me to access the ancestor that is one level above,
but not the ones that are on top of it. Thanks a lot.


Best
 

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