1

I have a class called Animal. For any given animal a, a.number_of_legs should be 4.

I have a class called Human which inherits from Animal. For any given human h, h.number_of_legs should be 2.

How do I set up the number_of_legs property?


Here's what I have so far:

 class Animal {
      int number_of_legs = 4;
 }

 class Human : Animal {
      int number_of_legs = 2;
 }

But if I take some arbitrary animal and ask how many legs it has, the answer is always 2:

 Animal x = new Animal();
 Animal y = new Human();
 x.number_of_legs // --> 4
 y.number_of_legs // --> 4

I understand that this new Human is being treated as an Animal because the variable y stores an Animal.

How do I set up the number_of_legs property so that x.number_of_legs is 4 and y.number_of_legs is 2?

Joe
  • 3,804
  • 7
  • 35
  • 55

3 Answers3

5

First of all, you should be using actual C# properties for publicly accessible values like this, not public fields.

Mark the property virtual in the base class so it can be overridden in derived classes.

public class Animal {

    // By default, Animals will have 4 legs.
    public virtual int NumberOfLegs { get { return 4; } }
}

Then override it in the derived class to provide a different implementation.

public class Human : Animal {

    // But humans have 2 legs.
    public override int NumberOfLegs { get { return 2; } }
}
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • Is there a way to make a virtual field in C#? – Joe Mar 27 '13 at 03:42
  • 2
    No. A field is just a location in memory, where the variable is stored. `virtual` calls go through a vtable, which determines which functions are called depending on the object type, regardless of the type of the variable reference. Properties are essentially just `get` and `set` methods. – Jonathon Reinhart Mar 27 '13 at 03:45
  • I should confess I didn't know these. – Hossein Narimani Rad Mar 27 '13 at 03:57
  • @HosseinNarimaniRad I know you didn't. That's why I called you out on it. [Plagiarism](http://en.wikipedia.org/wiki/Plagiarism) is not cool. – Jonathon Reinhart Mar 27 '13 at 04:26
1

try this ...

namespace StackOverflow
{
    public class Animal
    {
        public int Legs { get; set; }
        public Animal() { Legs = 4;  }
        public Animal(int legs) { Legs = legs; }
    }
    public class Human : Animal
    {
        public Human() : base(2) { }
    }
}
Paul
  • 19
  • 1
  • 1
    `Animal a = new Animal(42); a.Legs = 1337;` Not sure this is what the OP wants. – Jonathon Reinhart Mar 27 '13 at 03:49
  • the original question was: How do I set up the number_of_legs property so that x.number_of_legs is 4 and y.number_of_legs is 2? and not how to fix them it seems. So my answer is ok. – Paul Mar 27 '13 at 04:35
  • Right, but it seems unlikely that he'd want a client to be able to set the number of legs to an arbitrary value. You could fix this by making it a `private set` property. – Jonathon Reinhart Mar 27 '13 at 04:44
0

Joe, you can also try that ... (for multiple initializers in a derived class)

namespace StackOverflow
{
    public class Animal
    {
        public int Legs { get; set; }
        public string Color { get; set; }
        public string Origin { get; set; }

        public Animal() { Initialize(); }
        public virtual void Initialize() { Legs = 4; Color = "blue"; Origin = "everywhere"; }
    }

    public class Human : Animal
    {
        public Human() { }
        public override void Initialize() { Legs = 2; Color = "black"; Origin = "Africa"; }
    }

    public class Program
    {
        public static void main()
        {
            Animal a = new Animal();
            Animal h = new Human();
        }
    }
}
Paul
  • 19
  • 1
  • Not to mention, you're [calling a virtual method from a construtor](http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor). – Jonathon Reinhart Mar 27 '13 at 04:29
  • the original question was: How do I set up the number_of_legs property so that x.number_of_legs is 4 and y.number_of_legs is 2? and not how to fix them it seems. So my answer is ok. – Paul Mar 27 '13 at 04:42
  • virtual initializers in constructors is the good way to do cascading settings. The ascending call order of contructors doesnt permit natural descending initialisation (overriding base values). The best practice is to not instanciate with constructor but with a static class method in order to return a null value if initialisation fails. – Paul Mar 27 '13 at 04:44
  • so you can test for instanciation results (ie: that can fails in long garbage collection cases) – Paul Mar 27 '13 at 04:51
  • with this practice, you can also catch the good moment from Xml or DataContract Deserialize() process if your object is a Poco or EF5 class. – Paul Mar 27 '13 at 04:56
  • yes I stand corrected on that comment. You bring up good points, thank you. The important thing to remember is not access properties from derived classes, in any function that is called from a constructor. – Jonathon Reinhart Mar 27 '13 at 04:57