C# 继承和访问修饰符
我有以下简单的C代码,但我不理解输出C# 继承和访问修饰符,c#,inheritance,C#,Inheritance,我有以下简单的C代码,但我不理解输出 using System; namespace ConsoleApplication4 { class myParent { public int id = 3; private string name = "Parent class private string"; public void mymethod() { Console.WriteLine(
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
}
}
当我调用c1.mymethod()
时,为什么在myParent
类中使用string name
而不是myChild
类中使用string name
,因为我调用了myChild
对象上的方法,该对象具有定义的string name
变量
我曾经相信,继承意味着简单地将代码从基类复制粘贴到派生类,以重用代码或保存关键字。但经过一些研究,情况似乎并非如此。调用继承的方法会以某种方式引用基类,这可能会解释代码中的输出
然而,我仍然不清楚继承的内在作用。例如,我从未创建基类的实例。基类方法(myParent.mymethod()
)应该如何退出
请帮我澄清我的困惑,并给我指一些文档
当我调用c1.mymethod()时,为什么要使用myParent类中的string name而不是myChild类中的string name,因为我在调用myChild对象上的方法时,该对象具有已定义的string name变量
方法c1.mymethod()
仅在myParent
类中定义。因此,当您调用该方法时,它将使用最接近该方法的名称
。换句话说,它将首先在myParent
类中搜索该变量,如果找到,它将使用它
但是,如果您这样做了(将myMethod
设置为虚拟,并在myChild
中覆盖它):
然后它将使用myChild
类中的name
变量,因为这是最接近的变量
如果您这样做,您将遇到类似的情况:
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
}
}
根据C#规范:
以下是固有性的定义:
继承意味着一个类隐式地包含它的所有成员
直接基类类型,实例构造函数除外,
基类的析构函数和静态构造函数
现在,关于扩展基类
派生类扩展其直接基类。派生类可以添加
将新成员添加到它继承的成员,但它无法删除该定义
继承成员的
换句话说,您可以通过添加新定义(或覆盖现有定义)来扩展基类,但不能删除任何定义
为了让它更干净:
派生类可以通过声明新成员来隐藏(§3.7.1.2)继承的成员
具有相同姓名或签名的成员。但是请注意,隐藏
继承的成员不会删除该成员-它只会使
无法通过派生类直接访问成员
在派生类中执行的操作称为隐藏,从引号中可以看出,它不会删除该成员
因为在您的
MyParent
类中,您使用的是同一类中定义的name
字段,所以它将始终打印它所做的事情。要更改此行为,您应该查看属性。如果要访问派生类中的字段,可以将其定义为
并在子构造函数中设置它
class myChild : myParent
{
public myChild()
{
name = "Child class private string";
}
}
或者,如果将name
定义为属性{get;set;},则可以使用keyworkds
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";
}
我从未创建基类的实例
它是在实例化派生类时在内部创建的
当我调用c1.mymethod()时,为什么要使用myParent类中的string name而不是myChild类中的string name,因为我在调用myChild对象上的方法时,该对象具有已定义的string name变量
基本上,您的原始代码在其输出方面与上述情况相当,即在派生类中使用new
关键字的virtualname
class myChild : myParent
{
new string name { get; set; } = "Child class private string";
}
在这种情况下,父级方法将显示父级的
名称
,因为子级的名称
现在是一个不同的新变量,并且不再是父级方法中使用的变量。Private是对字段最严格的访问。这意味着没有其他类可以访问它,只有当前类。每个类都有自己的私有字段集
应用程序的行为类似于此的原因是您的mymethod()
成员已声明为public。这意味着任何类都可以调用它。由于您继承了该方法,因此可以在myParent
中自动获取该方法。它不是复制到myparent
,而是继承的。由于它没有被myChild
覆盖,对myChild.mymethod()
的调用将在myParent
上调用它,这将访问它可以访问的唯一私有name
字段(在myParent
中)
如果要继承name字段,使其行为更像预期的那样,则需要将该字段设置为受保护的,而不是私有的
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";
}
}
现在,
myParent
中的变量在实例化时被myChild
覆盖。因此,当您调用myChild.mymethod()
时,它可以访问新值。您在myChild
类中的新字段name
不会使基类中继承的字段name
消失!它就藏在里面。好的,它已经隐藏了,因为它是私有的,但是在派生类中引入一个新字段仍然不会使隐藏字段消失
如果需要只读的名称
,可以使用不带设置
访问器的受保护的虚拟
属性,并在派生类中重写它:
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";
}
如果要将其保留为私有
字段,请提供派生类可以链接的构造函数:
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")
{
}
}
这是因为您在父级上下文中使用了一个方法。由于您尚未重写myMethod(),因此将使用priva
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";
}
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")
{
}
}
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
}
}
static void Main(string[] args)
{
myParent c1 = new myChild();
c1.mymethod();
Console.ReadLine();
}