4

Suppose we have code like this:

interface I
{
    int P { get; }
}

class A : I
{
    public virtual int P { get { return 0; } }
}

class B : A
{
    public override int P { get { return 1; } }
}

class C : B, I
{
    public int P { get { return 2; } }
}

A c = new C();
I ic = new C();

Now the question is what whould be c.P and ic.P? Actually I know it will be 1 and 2, but can you explain me why?

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
Stas Yarkin
  • 126
  • 4

5 Answers5

18

In the case of A c = new C();, it's going to call the first function it finds that correctly overrides the function declared in A. Since C.P doesn't override it, but hides it, the virtual tree traversal (polymorphic resolution) won't call the C.P function, it'll instead call the lowest one in the inheritance tree, which is B.P.

In the case of I ic = new C();, it will happily call the direct interface implementation of P, since it's not concerned with a polymorphic virtual call, so in that case it calls C.P.

Note: it's key here that C has I directly in its inheritance declaration (i.e. looks like class C : B, I instead of class C : B) for this behavior. If it did not, the ic.P call would again refer to the overridden inherited P just like c.P, and would also return 1.

You should see a warning that says the following, which helps give you a clue that something isn't done quite right:

'C.P' hides inherited member 'B.P'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

Gjeltema
  • 4,122
  • 2
  • 24
  • 31
  • 1
    I think this answer is fine but still misses something. The question is also about which method is "mapped" to be the implementation of the interface. It is here very important that the class `C` mentions the interface `I` _again_, in the declaration `class C : B, I`. Because without this "repetition" of `I`, the type `C` would still implement `I` because of inheritance from `A`. But if we had just `class C : B` without mention of `I` there, the result would differ. I suggest the asker reads the section ***Interface re-implementation*** in the _C# Language Specification_. – Jeppe Stig Nielsen May 19 '13 at 21:17
  • @JeppeStigNielsen Good point, I should have more explicitly mentioned that. I referenced to the direct implementation that C has of I, but after re-reading, I can see how that might be a point missed by a reader. I'll update. – Gjeltema May 19 '13 at 22:25
2

class B : A means that class B inherits class A , in simple words means that class B will have all the properties-functions that class A has. BUT when you say public override int P , (the "key word" is override) means that for 'P' class B will behave in a different way. It's like "hiding" the class A for 'P'.

More useful is to read documentation:

Inheritance

0

This Page is very relevant to your post. In this case, what happens depends on what is viewed as the current type. So, for c, P is 1, because it's using the P method from A, which was overriden by B. It's calling the method that is furthest down the child chain that is still the method for A. For ic, the method is called for the furthest down the child chain again, this time at C, because it is a valid implementation of the method present in I. This doesn't happen in the first case because A.P is not overridden by C.P.

Mike Precup
  • 4,148
  • 21
  • 41
0

Let's analyze each one:

A c = new C();

Class A implements P as virtual method. Subclasses need to declare P adding the override modifier in order to actually override it (MSDN reference):

The override modifier is required to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.

Now the second:

I ic = new C();

Interface I doesn't (obviously) implement method P, neither declare it as virtual (although it's implicitly defined as virtual sealed), which means that the implementation of the instance that is late-bound to ic (early-bound to interface I) will be used.

Nadir Sampaoli
  • 5,437
  • 4
  • 22
  • 32
0

It should be 2 and 2.

It's 1 and 2 because you have not implemented P in C properly. It hides P in B. C should be:

class C : B, I
{
    public override int P { get { return 2; } }
}

Keyword override is needed here and if you absolutely need to have it this way (to have 1 ans 2 as object states), you need to use new keyword:

class C : B, I
{
    public new int P { get { return 2; } }
}

And if you are using Visual Studio, you should have seen a warning for this.

Kaveh Shahbazian
  • 13,088
  • 13
  • 80
  • 139