【问题标题】:Polymorphism unexpected results多态性意外结果
【发布时间】:2014-08-27 13:49:20
【问题描述】:

为了进一步了解多态性,我构建了一个小测试,它返回了意想不到的结果。

所以想法是用 virtual/override 关键字覆盖基类方法,但似乎我不需要这些?

public class Employee 
        {
            public Employee()
            {
                this.firstName = "Terry";
                this.lastName = "Wingfield";
            }

            public string firstName { get; set; }
            public string lastName { get; set; }

            public void writeName()
            {
                Console.WriteLine(this.firstName + " " + this.lastName);
                Console.ReadLine();
            }
        }

        public class PartTimeEmployee : Employee 
        {
            public void writeName() 
            {
                Console.WriteLine("John" + " " + "Doe");
                Console.ReadLine();
            }
        }
        public class FullTimeEmployee : Employee 
        {
            public void writeName()
            {
                Console.WriteLine("Jane" + " " + "Doe");
                Console.ReadLine();
            }
        }

        static void Main(string[] args)
        {
            Employee employee = new Employee();
            PartTimeEmployee partTimeEmployee = new PartTimeEmployee();
            FullTimeEmployee fullTimeEmployee = new FullTimeEmployee();

            employee.writeName();
            partTimeEmployee.writeName();
            fullTimeEmployee.writeName();
        }
    }

使用上面的代码,我期待这样的结果:

  1. 特里·维格菲尔德
  2. 特里·温菲尔德
  3. 特里·温菲尔德

但下面的内容被写入控制台:

  1. 特里·温菲尔德
  2. 约翰·多伊
  3. 简·多伊

我认为后者不起作用,因为它需要 ovrride 关键字。

所以问题是为什么我看到后面的名字没有适当的关键字?

我希望这足够清楚,可以阅读。

问候,

【问题讨论】:

  • 这是因为子类中的writeName()隐藏基类中的版本(您应该已经看到了关于此的编译器警告)。如果你将这三个都转换为Employees,你应该会看到第一个结果。
  • @JLRishe 非常感谢。

标签: c# class polymorphism


【解决方案1】:

您展示的代码中没有多态性。

改成:

Employee employee = new Employee();
Employee partTimeEmployee = new PartTimeEmployee();
Employee fullTimeEmployee = new FullTimeEmployee();

你会得到你预期的结果。

更新:

OOP 中“多态”(多种形式)的概念意味着代码处理特定类型(基类或接口)的引用,而这些引用背后可能存在不同类型的实例(后代、实现)。要“启动”多态性,必须有继承和虚拟方法(在接口实现的情况下使用不同的术语,但让我们使用与您的代码示例相关的术语)。您有继承,但没有虚拟方法。对于常规(非虚拟)方法,方法调用在编译时根据被调用方法的对象类型来解析。

代码:

PartTimeEmployee partTimeEmployee = ...;
partTimeEmployee.writeName();

编译器很清楚要调用什么方法writeName,它就是PartTimeEmployee.writeName。 同样,对于代码:

Employee partTimeEmployee = ...;
partTimeEmployee.writeName();

调用的方法是Employee.writeName

【讨论】:

  • 考虑到您在答案中提供了代码,我会将其标记为已回答。如果我可以问,以帮助未来的“读者”。为什么需要引用基类来实例化多态行为的子类?谢谢。
  • 谢谢。与您的答案相匹配的重要信息更新。
【解决方案2】:

这称为方法隐藏。您只是将基类方法隐藏在派生类中。你应该收到警告,但这是完全合法的。有关详细信息,请参阅documentation。您可能还想看看this question

【讨论】:

  • 这没有回答他的问题。他问的是方法实现的多态性,以及为什么在他不使用覆盖时调用基类方法的实现。
  • @Alan 隐藏方法确实解释了他所看到的行为。
  • 他的问题是为什么他不使用覆盖就无法获得基类方法的实现。正确的答案是,因为他没有使用对基类类型的引用。他正在尝试测试是否使用虚拟方法之间的区别。而且通过使用基本类型的变量(他的错误),无论是否隐藏方法,他都无法证明这一点。
  • @Selman22 感谢您的评论,但这确实没有回答我的问题。这当然是问题的一部分,但不是全部。无论如何,我感谢所有帮助我解决问题的时间。
【解决方案3】:

对于多态行为,您必须 override PartTimeEmployeeFullTimeEmployee 中的那些方法。您在那里所做的是将方法隐藏在基类中。

        public class Employee 
        {
            public Employee()
            {
                this.firstName = "Terry";
                this.lastName = "Wingfield";
            }

            public string firstName { get; set; }
            public string lastName { get; set; }

            public virtual void writeName()
            {
                Console.WriteLine(this.firstName + " " + this.lastName);
                Console.ReadLine();
            }
        }

    public class PartTimeEmployee : Employee 
    {
        public override void writeName() 
        {
            Console.WriteLine("John" + " " + "Doe");
            Console.ReadLine();
        }
    }
    public class FullTimeEmployee : Employee 
    {
        public override void writeName()
        {
            Console.WriteLine("Jane" + " " + "Doe");
            Console.ReadLine();
        }
    }

【讨论】:

  • 我看到您在实例化子类时添加了 Virtual/Override 关键字,但没有提及引用基类。感谢您的宝贵时间。
【解决方案4】:

使用 C#,您可以使用“new”关键字重写基类的方法。如果您省略此关键字,编译器将编译您的源代码,就好像它存在一样。 所以我认为问题是:new 和 override 有什么区别?差别很大。

“new”指示编译器使用您的实现而不是基类实现,但任何不直接引用您的类的代码都将使用基类实现。

“覆盖”用于虚拟和抽象方法。这指示编译器使用方法的最后定义实现。如果在对基类的引用上调用该方法,它将使用在该对象上覆盖它的最后一个实现。

我希望我已经足够清楚了。

【讨论】:

  • 内容丰富的评论,但可能与主题无关。我了解正在发生的事情以及应该输出的内容,但是代码中有一个“错误”错字。还是很棒的评论!将帮助未来的“读者”。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-26
  • 2013-12-31
  • 2012-10-09
  • 2018-09-04
  • 2017-06-02
  • 2021-11-11
相关资源
最近更新 更多