C# 为什么在初始化子对象并将其分配给父对象时调用父方法
我想声明一个父变量,然后给它分配一个子对象 当父变量调用方法(存在于父/子变量中)时,它应该使用子变量的版本C# 为什么在初始化子对象并将其分配给父对象时调用父方法,c#,methods,overriding,parent,C#,Methods,Overriding,Parent,我想声明一个父变量,然后给它分配一个子对象 当父变量调用方法(存在于父/子变量中)时,它应该使用子变量的版本 public abstract class TowInt { public int One; public int Two; public char Operator; public int Result; public int Remainder; public void init() { calc();
public abstract class TowInt
{
public int One;
public int Two;
public char Operator;
public int Result;
public int Remainder;
public void init()
{
calc();
}
protected abstract void calc();
public string getAnswer()
{
return Convert.ToString(Result);
}
public string getQuestion()
{
return string.Format("{0} {1} {2} = ", One, Operator, Two);
}
}
public class TwoIntPlus : TowInt
{
public TwoIntPlus(int one, int two)
{
One = one;
Two = two;
Operator = '+';
}
protected override void calc()
{
Result = One + Two;
}
}
public class TwoIntDivision : TowInt
{
public TwoIntDivision(int one, int two)
{
One = one;
Two = two;
Operator = '/';
}
protected override void calc()
{
Result = One / Two;
Remainder = One % Two;
}
new public virtual string getAnswer()
{
return string.Format("{0}R{1}", Result, Remainder);
}
}
using System.IO;
class ConsoleApplication1
{
static void Main()
{
// For child class, the child method getAnswer() is called
TwoIntDivision n2 = new TwoIntDivision(32, 4);
n2.init();
Console.WriteLine(n2.getQuestion() + n2.getAnswer());
// 32 / 4 = 8R0 -- this is what I expected
// If assign a child object to parent, then the parent method is called
TowInt two;
two = new TwoIntDivision(32, 4);
two.init();
Console.WriteLine(two.getQuestion() + two.getAnswer());
// 32 /4 = 8 -- this is not what I expected
two = new TwoIntPlus(32, 4);
two.init();
Console.WriteLine(two.getQuestion() + two.getAnswer());
Thread.Sleep(5000);
}
}
代码的问题在于,您没有在基类中将
getAnswer
方法标记为virtual
因此,在您要隐藏的TwoIntDivision
类中,不重写(扩展)基类方法:
// this is hiding the base class method, not overriding it (notice the new modifier)
new public virtual string getAnswer()
然后,在强制转换对象时,根据对象的类型,它将使用您正在使用的类型的方法。这完全是预期的行为,在正确的上下文中可以派上用场
要获得预期的行为,请修改如下定义:
public abstract class TowInt
{
public virtual string getAnswer() {
return "Hello from Base-Class";
}
}
public class TwoIntDivision : TowInt
{
public override string getAnswer() {
return "Hello from Division";
}
}
TowInt t = new TwoIntDivision();
Console.WriteLine(t.getAnswer()); // prints "Hello from Division"
作为旁注,如果您来自Java背景,在C#中,默认情况下方法是最终的(非虚拟的)。如果要允许在派生类中重写方法,则必须使用
virtual
修饰符显式标记该方法。请仅将相关代码发布到您遇到的问题。TL;博士-试着把重点放在与你的问题相关的代码上。并且清楚地说明你的问题实际上是什么……而且,C#不是java。使用属性而不是get/set方法。当实例化division对象时,为什么不期望32/4=8?这对我来说似乎是正确的行为。。。如果只是格式,您没有在基类中将其标记为virtual
。甚至没有注意到他有new
要隐藏,尽管我注意到虚拟的位置不正确。接得好!表示Java背景的其他一些东西包括camelCase
方法名称,而不是PascalCase
方法名称,以及将大括号放在与方法名称相同的行上,第一个大括号放在答案中,您在回答中特别应用了第二个方法。不使用virtual in parent方法的原因是我不希望每个子类都重写该函数(getAnswer()对于+-*除了/,是相同的)。我只想让TwoIntDivision覆盖它。是否有其他方法可以在不重写每个子类的情况下实现这一点?扩展基类的类不需要重写标记为virtual
的方法。唯一必须重写的方法是标记为abstract
(以及仅由初始类扩展抽象类)的方法。virtual
修饰符只是向CLR指示该方法可能被更特定的类重写。