Reputation:
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
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
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
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
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
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
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