5

I am trying to understand the way inheritance works in C#. Basically, I have a base class Base that has a simple function sayIt. The function makes use of a property "i" that is redefined in subclasses. Here, it is redefined as 1 from 0. When I run this program, I get "0" as output rather than "1" which is what I expected (because in python I would get 1). Can anyone explain why, and more importantly, whether this is a pattern that is supported in C#?

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        Console.WriteLine(d.sayIt());
        Console.ReadLine();
    }
}

class Base
{
    int _i = 0;
    public int i
    {
        get { return _i; }

    }

    public String sayIt()
    {
        return Convert.ToString(this.i);
    }
}

class Derived : Base
{
    int _i = 1;
    public new int i
    {
        get { return _i; }
    }
}
2
  • see en.wikipedia.org/wiki/Object_slicing, it is not something you want to do without a very good reason. Commented Jan 7, 2014 at 0:47
  • I'm not adding anything to Base: I'm merely redefining some things, so I'm not opening myself up to slicing. Commented Jan 7, 2014 at 1:01

5 Answers 5

8
  1. Mark the property as virtual within Base class

  2. Replace new with override next to the property within Derived class.

1. Is necessary because members are non-virtual in c# by default. and 2. is necessary, because using new would break the virtual resolving pass, what is not what your want.

There is nice article about new and override on MSDN: Knowing When to Use Override and New Keywords (C# Programming Guide).

The override modifier extends the base class method, and the new modifier hides it.

Sign up to request clarification or add additional context in comments.

3 Comments

When you instantiate a Derived, are there two copies of _i or not? sayIt is obviously calling the i property on the class in which it is defined (Base) (because it's non-virtual) but that doesn't explain why the property itself is pulling _i from the same class too, unless there's secretly two copies of _i, which begs the question, how does one tell them apart?
Both _i fields exist. and sayIt is not pulling _i directly: it pulls i property which is virtual, so Derived.i is taken and it calls proper _i.
QUite a nice explanation. +1.
3

In order to have a function that can be overriden by a derived type you need to make it virtual

public virtual int i
{
  get { return _i; }
}

Then in the derived type you can override the behavior with the override keyword

public override int i
{
  get { return _i; }
}

Comments

3

In C# you have the option to NOT allow full polymorphic/inheritance behavior in your classes.

In order to get your expected output your code should look like this: (didn't test)

class Base
{
    int _i = 0;
    public virtual int i
    {
        get { return _i; }

    }

    public String sayIt()
    {
        return Convert.ToString(this.i);
    }
}

class Derived : Base
{
    int _i = 1;
    public override int i
    {
        get { return _i; }
    }
}

Now you are telling the C# interpreter that i is "virtual" or the underlying representation can be overridden by child classes.

In your old code, you are calling sayIt() which is in Base(). Since i is NOT virtual, it does not look for a child porperty that has been overridden.

Basically in C#, in order to have proper inheritance and polymorphism your code needs explicit declaration in syntax by the use of "virtual" then "override".

Comments

0

As others have mentioned change the property i to virtual in the Base and use override in the property in the Derived class. See below example for the output for each case to understand it better. You can see that you get different output for Option 2.

class Base
{
    int _i = 0;
    public virtual int i
    {
        get { return _i; }
    }

    public String sayIt()
    {
        return Convert.ToString(this.i);
    }
}

class Derived : Base
{
    int _i = 1;
    public override int i
    {
        get { return _i; }
    }
}

You can instantiate the code in 3 different ways:

// Option 1
Base a = new Base();
Console.WriteLine(a.i);
// Output using virtual/override --> 0
// Output using new --> 0


// Option 2
Base b = new Derived();
Console.WriteLine(b.i);
// Output using virtual/override --> 1
// Output using new --> 0

// Option 3
Derived c = new Derived();
Console.WriteLine(c.i);
// Output using virtual/override --> 1
// Output using new --> 1

// Option 2
// Derived d = new Base();
// Console.WriteLine(d.i);
// This won't obviously compile

Comments

0

The confusion is because you are technically using name hiding in the derived class instead of overriding the base class' behavior. When using member hiding, the type you have the reference to dictates which method actually runs as both exist. New allows you to indicate you intended to "hide" the base implementation for those specifically calling your method on the designated type. To illustrate:

class Program
    {
        static void Main(string[] args)
        {
            //both 'i' properties exist
            Derived d = new Derived();

            Console.WriteLine(d.i);  // uses the 'i' for this type
            Console.WriteLine(((Base)d).i); // uses the 'i' for this type
            Console.ReadLine();
        }
    }

class Base
{
    int _i = 0;
    public  int i
    {
        get { return _i; }

    }

    public String sayIt()
    {
        //this class and this method doesn't realize the derived class has hid this.i
        return Convert.ToString(this.i);
    }
}

class Derived : Base
{
    int _i = 1;
    public new int i
    {
        get { return _i; }
    }
}

This is what you want I believe to achieve the pattern.

class Base
{
    int _i = 0;
    public  virtual int i
    {
        get { return _i; }

    }

    public String sayIt()
    {
        return Convert.ToString(this.i);
    }
}

class Derived : Base
{
    int _i = 1;
    public override int i
    {
        get { return _i; }
    }
}

Hope that helps.

-dw

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.