user6338533
user6338533

Reputation:

Inheritance and access modifier

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.

Upvotes: 2

Views: 3560

Answers (6)

NightOwl888
NightOwl888

Reputation: 56859

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.

Upvotes: 3

user6996876
user6996876

Reputation:

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.

Upvotes: 0

Erangad
Erangad

Reputation: 861

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();
}

Upvotes: 0

Jeppe Stig Nielsen
Jeppe Stig Nielsen

Reputation: 61952

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")
    {
    }
}

Upvotes: 0

CodingYoshi
CodingYoshi

Reputation: 27009

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
    }
}

Upvotes: 0

bot_insane
bot_insane

Reputation: 2604

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.

Upvotes: 0

Related Questions