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指示该方法可能被更特定的类重写。