2

I have the following simple C# code, but I do not understand the output.

using System;

namespace ConsoleApplication4
{
    class myParent
    {
        public int id = 3;
        private string name = "Parent class private string";
        public void mymethod()
        {
            Console.WriteLine("{0} & {1}", name, id);
        }
    }

    class myChild : myParent
    {
        private string name = "Child class private string";
    }

    class Program
    {
        static void Main(string[] args)
        {
            myChild c1 = new myChild();  
            c1.mymethod();
            Console.ReadLine();
        }

        //Output
        //Parent class private string & 3
    }
}

When I invoke c1.mymethod(), why is string name in the myParent class used instead of string name in myChild class since I am invoking a method on myChild object which has a defined string name variable?

I used to believe that inheritance means simply virtually copying and pasting code from a base class to a derived class to reuse code or save key stroke. But after some research, this doesn't seem to be the case. Invoking a inherited method somehow references the base class, which might explains the output in my code.

However, I am still not clear about the inner working of inheritance. For example, I never created an instance of the base class. How should the base class method ( myParent.mymethod() ) exit?

Please help clarity my confusion and point me to some documentations.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • There is already an answer to your question [here](http://stackoverflow.com/a/2950842/2679750) – Mark C. Feb 05 '17 at 15:11
  • 4
    Possible duplicate of [Are private members inherited in C#?](http://stackoverflow.com/questions/2950820/are-private-members-inherited-in-c) – krillgar Feb 05 '17 at 15:14
  • 1
    *runtime Polymorphism* does not apply to fields regardless of whether they are `private` or not. – Chetan Kinger Feb 05 '17 at 15:16
  • Thanks for the link. Most intro level tutorials dont make the distinction between accessiblity and inheritance when it comes to private fields. –  Feb 05 '17 at 15:35
  • c1.mymethod() is just a call to mymethod() which is defined in the parent class. Since you already know why the derived class has access to the base class' public method, this method is using a private field 'name' which is completely legal since this private field is accessed by the same class' method not c1 object. – Yawar Murtaza Feb 05 '17 at 15:45
  • 1
    What do you mean "I never created an instance of the base class"? When a cow is born, a mammal is born, i.e. the cow. – Kris Vandermotten Feb 05 '17 at 15:52
  • @Kris that was a silly of me. I have always much better understanding now after everyone's input. Thanks everyone. –  Feb 05 '17 at 18:17

6 Answers6

3

Private is the most restrictive access for a field. It means that no other class has access to it, only the current one. Each class has its own set of private fields.

The reason why your application behaves like this is because your mymethod() member is declared public. That means that any class can call it. Since you are inheriting it, you automatically get that method in myParent. It is not copied into myparent, it is inherited. And since it is not overridden by myChild a call to myChild.mymethod() will invoke it on myParent, which accesses the only private name field it can (the one inside myParent).

If you want to inherit the name field, so it will act more like you are expecting, you need to make the field protected instead of private.

class myParent
{
    public int id = 3;
    protected string name = "Parent class private string";
    public void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

class myChild : myParent
{
    public myChild()
    {
        name = "Child class private string";
    }
}

Now the variable in myParent is overwritten by myChild when it is instantiated. So, when you make a call to myChild.mymethod() it has access to the new value.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • *If you want to inherit the name field, so it will act more like you are expecting, you need to make the field protected instead of private.*. That sounds misleading. You will also need to *override* the method which you already mentioned but the statement is misleading on its own. – Chetan Kinger Feb 05 '17 at 15:35
  • @CKing no, making the field protected *and* setting the field in the child's c.tor is enough: you don't need to override the method, look also at my answer, I'm saying the same thing –  Feb 05 '17 at 15:41
  • @user1892538 What I was trying to say is that simply making the field *protected* in the base class and leaving the rest of the code as-is will not work. – Chetan Kinger Feb 05 '17 at 15:43
  • So a base class/object never actually "owns" what it inherits? It can only use the inherited members which will result in referrencing the base class? –  Feb 05 '17 at 16:09
  • Should be "derived clasd" in my last comment. –  Feb 05 '17 at 16:10
  • @JohnSmithSr. - Each class has its own private/protected/public/internal scopes (in addition internal and protected can be applied at the same time). Private scope is completely separate in each layer of inheritance, but protected scope of a field means that every class that inherits it can read/write that field. – NightOwl888 Feb 05 '17 at 16:38
  • @CKing - Why would you say it is misleading? Making the field protected is enough for both the base class and derived class to be able to access it. The issue is the OP has 2 different variables instead of one. – NightOwl888 Feb 05 '17 at 16:39
0

When I invoke c1.mymethod(), why is string name in the myParent class used instead of string name in myChild class since I am invoking a method on myChild object which has a defined string name variable?

The method c1.mymethod() is defined only in myParent class. Therefore, when you invoke the method, it is going to use the name found in closest proximity to that method. In other words, it will first search the myParent class for that variable and if found it will use it.

If you did this however (make myMethod virtual and override it in the myChild):

class myParent
{
    public int id = 3;
    private string name = "Parent class private string";
    public virtual void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

class myChild : myParent
{
    private string name = "Child class private string";
    public override void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

Then it will use the name variable from myChild class since that is the closest one.

You will run into a similar situation if you did this:

public class Person
{
    private string name = "John";
    public Person(string name)
    {
        // The parameter is named `name` and the field is named `name` 
        // so the compiler is going to choose the closest variable.
        // In this case, it will assign `name` parameter to itself.
        // Visual Studio is nice, in this case, to give you a warning but 
        // your code will compile and the compiler will just assign `name`
        // to `name`
        name = name;

        // If you did this: this.name = name; 
        // then the private field will be assigned the value of the parameter
    }
}
CodingYoshi
  • 25,467
  • 4
  • 62
  • 64
  • If the base class private field is not found for the method, the compile will NOT use derived class private field because it is simply an entirely different field? –  Feb 05 '17 at 18:29
  • If it is not found in your base class then you will not even be able to compile your base class because your base class has no idea if someone will derive from it or not and it needs the field for the method. – CodingYoshi Feb 05 '17 at 19:03
  • Ha, that makes sense. Thanks –  Feb 05 '17 at 19:05
  • Do you need any more clarity or have I answered your question? – CodingYoshi Feb 07 '17 at 04:16
0

From C# specification:

Here is how Inhertiance is defined:

Inheritance means that a class implicitly contains all members of its direct base class type, except for the instance constructors, destructors and static constructors of the base class.

Now about extending base class.

A derived class extends its direct base class. A derived class can add new members to those it inherits, but it cannot remove the definition of an inherited member.

In other word you can extended base class by adding new definitions (or overriding existing ones), but you can't remove any.

And to get it more cleaner:

A derived class can hide (§3.7.1.2) inherited members by declaring new members with the same name or signature. Note however that hiding an inherited member does not remove that member—it merely makes that member inaccessible directly through the derived class.

What you do in your derived class is called hiding and as you can see from quote it doesnt remove that member.

And because in your MyParent class you are using name field defined in same class it will always print what it does. For changing this behaviour you should have look at Virtual properties.

bot_insane
  • 2,545
  • 18
  • 40
  • Is it posible to hide a private member? –  Feb 05 '17 at 16:13
  • @JohnSmithSr. - I would say no, since by definition, a private member is hidden to all other classes but the current one. I private member cannot be hidden because it already *is* hidden. – NightOwl888 Feb 06 '17 at 05:18
0

If you want to access a field in the derived class, you can define it as protected.

class myParent
{
    public int id = 3;
    protected string name = "Parent class private string";
    public void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

and set it in the child constructor

class myChild : myParent
{
    public myChild()
    {
        name = "Child class private string";
    }
}

Alternatively you can use the virtual/override keyworkds if you define name as a property { get; set; }

class myParent
{
    public int id = 3;
    protected virtual string name { get; set; } = "Parent class private string";
    public void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

class myChild : myParent
{
    protected override string name { get; set; } = "Child class private string";
}

I never created an instance of the base class.

It is created internally when you instantiate the derived class.

When I invoke c1.mymethod(), why is string name in the myParent class used instead of string name in myChild class since I am invoking a method on myChild object which has a defined string name variable?

Basically your original code is equivalent - in terms of its output - to the above case of a virtual name with a new keyword in the derived class

class myChild : myParent
{
    new string name { get; set; } = "Child class private string";
}

In that case, the parent's method will display the parent's name, since the child's name is now a different, new variable and it's no longer the one used in the parent's method.

  • Thanks. Does the statement always hold that a base class instance get created when instantiating a child class? What about creating multiple child class insdtances? –  Feb 05 '17 at 15:52
  • The statement means that all the members of the base class are internally created for the derived class. If you create multiple instances, only static variables are allocated once... –  Feb 05 '17 at 15:56
0

Your new field name in the myChild class does not make the inherited field name from the base class go away! It just hides in. OK, it was hidden already because it was private, but introducing a new field in the derived class still does not make the hidden field go away.

If you want a name that is read-only, you can use a protected virtual property with no set accessor, and override it in the deriving class:

class myParent
{
    public int id = 3;
    protected virtual string name => "Parent class private string";
    public void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

class myChild : myParent
{
    protected override string name => "Child class private string";
}

If you want to keep it as a private field, offer a constructor that the deriving class can chain:

class myParent
{
    public int id = 3;
    private string name;

    public myParent() : this("Parent class private string")
    {
    }
    protected myParent(string name)
    {
        this.name = name;
    }

    public void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

class myChild : myParent
{
    public myChild() : base("Child class private string")
    {
    }
}
Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • My first example is with `name` being a ___property___ which I also wrote. It is a valid example. Of course a ___field___ cannot be virtual, I agree. – Jeppe Stig Nielsen Feb 07 '17 at 23:49
0

This happens because you have used a method inside the parent's context. As you have not overridden myMethod() it will get executed using the private field in that parent's context. if you use method overriding here when you want to get the name of the child's context you can create a child object.

namespace ConsoleApplication2
{
class myParent
{
    public int id = 3;
    private string name = "Parent class private string";
    public void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

class myChild : myParent
{
    private string name = "Child class private string";
    public new void mymethod()
    {
        Console.WriteLine("{0} & {1}", name, id);
    }
}

class Program
{
    static void Main(string[] args)
    {
        myChild c1 = new myChild();
        c1.mymethod();
        Console.ReadLine();
    }

    //Output
    //Parent class private string & 3
}
}

If you want to get the name of the parent's context you can get that using a parent object.

static void Main(string[] args)
{
    myParent c1 = new myChild();
    c1.mymethod();
    Console.ReadLine();
}
Erangad
  • 671
  • 7
  • 16