C# 简单继承不起作用?

C# 简单继承不起作用?,c#,C#,我似乎忘记了一些最基本的继承规则,因为我不明白为什么这不起作用。我有一个扩展Node的类SuffixNode 节点: 我相信这是一个非常简单的答案,但我就是不明白为什么这不起作用。不应该 Node n = new SuffixNode(parent) 允许我访问SuffixNode方法和变量吗?您需要将AddLocation方法移动到基类。您需要将AddLocation方法移动到基类 Node n=new SuffixNode(parent) 这一行告诉编译器n是Node类型。它当前有一个S

我似乎忘记了一些最基本的继承规则,因为我不明白为什么这不起作用。我有一个扩展Node的类SuffixNode

节点:

我相信这是一个非常简单的答案,但我就是不明白为什么这不起作用。不应该

Node n = new SuffixNode(parent)

允许我访问SuffixNode方法和变量吗?

您需要将AddLocation方法移动到基类。

您需要将AddLocation方法移动到基类

Node n=new SuffixNode(parent)
这一行告诉编译器n是Node类型。它当前有一个SuffixNode分配给它这一事实与此无关。编译器只知道它是一个节点,因此只能调用它上的节点成员

可能最简单的解决方法是:

n = new SuffixNode(parent);
((SuffixNode)n).AddLocation(document, offset);
这基本上告诉编译器这里确实有一个后缀节点

可能更清楚的是:

SuffixNode sn = new SuffixNode(parent);
sn.AddLocation(document, offset);
n = sn;
这一行告诉编译器n是Node类型。它当前有一个SuffixNode分配给它这一事实与此无关。编译器只知道它是一个节点,因此只能调用它上的节点成员

可能最简单的解决方法是:

n = new SuffixNode(parent);
((SuffixNode)n).AddLocation(document, offset);
这基本上告诉编译器这里确实有一个后缀节点

可能更清楚的是:

SuffixNode sn = new SuffixNode(parent);
sn.AddLocation(document, offset);
n = sn;

您已经将n的类型声明为Node,实际上它没有AddLocation方法。您必须将其声明为SUFFEXNODE n=new SUFFEXNODEPARENT才能调用其上的子函数,或者向名为AddLocation的节点添加一个可能的抽象方法。

您已将n的类型声明为Node,实际上没有AddLocation方法。您必须将其声明为SUFFEXNODE n=new SUFFEXNODEPARENT,以便能够对其调用子函数,或者向名为AddLocation的节点添加一个可能是抽象的方法

Node n=new SuffixNodeparent不应该允许我访问SuffixNode方法和变量吗

不,变量的类型定义了您可以访问的方法

如果希望访问变量,则需要将其类型更改为SuffixNode

或者,您可以将其添加到基类中,如果这样做更有意义的话

Node n=new SuffixNodeparent不应该允许我访问SuffixNode方法和变量吗

不,变量的类型定义了您可以访问的方法

如果希望访问变量,则需要将其类型更改为SuffixNode


或者,如果这更有意义,您可以将其添加到基类中。

如果您在节点中定义虚拟方法,并在SuffixNode中重写它,那么将在您的场景中调用SuffixNode版本。如果在您的例子中,该方法在节点中不存在,则不能以这种方式调用它,因为变量n可以包含任何类型的节点。要调用该方法,首先必须将其强制转换为SuffixNode。

如果在Node中定义虚拟方法,并在SuffixNode中重写该方法,则将在场景中调用SuffixNode版本。如果在您的例子中,该方法在节点中不存在,则不能以这种方式调用它,因为变量n可以包含任何类型的节点。要调用该方法,首先必须将其强制转换为SuffixNode。

您已将n声明为节点。节点不包含AddLocation的定义,因此您的代码将不会编译。即使您知道实际的底层类型是SuffixNode,编译器也必须坚持自己的原则,并在出现错误时通知您

想象一下这个场景:

class OtherNode : Node
{

}

Node n = new OtherNode();
n.AddLocation(...);
这样行吗?当然不是,但有什么规则会在编译时忽略该代码并允许您的示例?编译器怎么可能知道您没有在程序的后期交换底层类型?不可能

你走错了路;如果此方法应可用于节点的所有后代,则至少需要在节点中声明它。它可以是抽象的,以便在派生类中重写。

您已将n声明为节点。节点不包含AddLocation的定义,因此您的代码将不会编译。即使您知道实际的底层类型是SuffixNode,编译器也必须坚持自己的原则,并在出现错误时通知您

想象一下这个场景:

class OtherNode : Node
{

}

Node n = new OtherNode();
n.AddLocation(...);
这样行吗?当然不是,但有什么规则会在编译时忽略该代码并允许您的示例?编译器怎么可能知道您没有在程序的后期交换底层类型?不可能


你走错了路;如果此方法应可用于节点的所有后代,则至少需要在节点中声明。它可以是抽象的,以便在派生类中重写。

许多答案都正确地指出,不能对类型为基类的变量调用派生类中定义的方法。没有人注意到这是C的静态类型提供的类型安全的基础

当你对一个变量调用一个方法时,方法c 所有这些都是在编译时解析的,当n是节点类型变量时,编译器无法解析n.AddLocation

另一种方法是在运行时解析调用,如果n的referent是没有AddLocation方法的其他Node子类的实例,或者实际上是Node本身的实例,则可能会导致异常。C类型系统是为了避免这种情况而明确设计的

考虑:

object o1 = "Hello, World!";
Console.WriteLine(o1.Length); //hypothetically fine

object o2 = Math.PI;
Console.WriteLine(o2.Length); //exception!
C语言的原理是快速失败:尽可能在编译时捕获编码错误,因为在编译时捕获的错误比在运行时捕获的错误更容易修复

在不改变对象模型的情况下,简单的解决方案是在相关块中引入一个新变量:

if (FirstChar == '$') 
{ 
    SuffixNode sn = new SuffixNode(parent); 
    sn.AddLocation(document, offset); 
    n = sn;
} 
else 
{ 
    n = new Node(parent, FirstChar); //Create a new node with the first char of the suffix as the label 
    parent.children.Add(FirstChar, n); //Add new node to the children collection of the parent 
} 

许多答案都正确地指出,不能对类型为基类的变量调用派生类中定义的方法。没有人注意到这是C的静态类型提供的类型安全的基础

当您对一个变量调用一个方法时,该方法调用将在编译时解析,当n是节点类型变量时,编译器无法解析n.AddLocation

另一种方法是在运行时解析调用,如果n的referent是没有AddLocation方法的其他Node子类的实例,或者实际上是Node本身的实例,则可能会导致异常。C类型系统是为了避免这种情况而明确设计的

考虑:

object o1 = "Hello, World!";
Console.WriteLine(o1.Length); //hypothetically fine

object o2 = Math.PI;
Console.WriteLine(o2.Length); //exception!
C语言的原理是快速失败:尽可能在编译时捕获编码错误,因为在编译时捕获的错误比在运行时捕获的错误更容易修复

在不改变对象模型的情况下,简单的解决方案是在相关块中引入一个新变量:

if (FirstChar == '$') 
{ 
    SuffixNode sn = new SuffixNode(parent); 
    sn.AddLocation(document, offset); 
    n = sn;
} 
else 
{ 
    n = new Node(parent, FirstChar); //Create a new node with the first char of the suffix as the label 
    parent.children.Add(FirstChar, n); //Add new node to the children collection of the parent 
} 

为什么要对n使用Node而不是suffix Node?我的树将包含不同类型的节点,我想如果以后我想使用一些多态方法,它会很有用。顺便说一句,我注意到if suffix==将永远不会执行,因为如果条件为真,前一行char FirstChar=suffix[0];是否会引发异常。相关?@phoog在没有后缀节点之前,我只使用普通节点尝试了这段代码,但遇到了这个问题,感谢您指出:为什么要使用Node而不是SuffixNode来表示n?我的树将包含不同类型的节点,我认为如果我以后想使用一些多态方法,它会很有用;是否会引发异常。相关?@phoog在没有后缀节点之前,我用普通节点尝试了这段代码,但遇到了这个问题,谢谢你指出:他不能将它声明为后缀节点,因为在if的另一个分支中,它有一个分配给它的节点。好的,在我的情况下,创建抽象方法最有意义,谢谢!这没有道理。抽象方法只能存在于抽象类中。您正在创建节点的一个具体实例,因此不能在其上放置抽象方法。您需要创建一个新的抽象类,或者创建一个新的类,该类可以从节点继承,并在当前创建节点的位置使用。另外,在代码中,AddLocation只在后缀类上有意义,因为它只写入该类中的私有变量。是否要在所有节点上添加位置?物体有这样的感觉有意义吗?很抱歉错过了显而易见的东西,工作了一整天,似乎很累。没错,Chris,AddLocation方法应该只在SuffixNode中。这里有足够的解释来帮助我,再次感谢你的帮助:@Chris:他可以在基类中创建一个虚拟方法,尽管这可能不是最好的解决方案。他不能将它声明为SuffixNode,因为在if的另一个分支中,它有一个分配给它的节点。好的,在我的例子中,创建抽象方法最有意义,谢谢这没有道理。抽象方法只能存在于抽象类中。您正在创建节点的一个具体实例,因此不能在其上放置抽象方法。您需要创建一个新的抽象类,或者创建一个新的类,该类可以从节点继承,并在当前创建节点的位置使用。另外,在代码中,AddLocation只在后缀类上有意义,因为它只写入该类中的私有变量。是否要在所有节点上添加位置?物体有这样的感觉有意义吗?很抱歉错过了显而易见的东西,工作了一整天,似乎很累。没错,Chris,AddLocation方法应该只在SuffixNode中。这里有足够的解释来帮助我,再次感谢你的帮助:@Chris:他可以在基类中创建一个虚拟方法,尽管这可能不是最好的解决方案。哦,对不起。。。那是因为你叫诺德
e、 AddLocation,它不存在。节点类型只知道它包含的内容。但您可以将Node取消绑定为后缀Node,并调用Node中包含的所有方法。相反,方法是派生类的成员,但变量的静态类型是基类。该变量可能包含假定类型PrefixNode的对象,该对象可能没有AddLocation方法。@phoog-谢谢。这就是我想说的:哦,对不起。。。这是因为您正在调用Node.AddLocation,它不存在。节点类型只知道它包含的内容。但您可以将Node取消绑定为后缀Node,并调用Node中包含的所有方法。相反,方法是派生类的成员,但变量的静态类型是基类。该变量可能包含假定类型PrefixNode的对象,该对象可能没有AddLocation方法。@phoog-谢谢。这就是我想说的:谢谢你的帮助!接受这个答案是因为你不仅提供了一个解决方案,而且还解释了为什么它不能以最好的方式工作。干杯谢谢你的帮助,菲欧!接受这个答案是因为你不仅提供了一个解决方案,而且还解释了为什么它不能以最好的方式工作。干杯