C# 多态性意外结果

C# 多态性意外结果,c#,class,polymorphism,C#,Class,Polymorphism,为了更好地理解多态性,我构建了一个小测试,它返回了意想不到的结果 所以我们的想法是用virtual/override关键字覆盖基类方法,但我似乎不需要这些 public class Employee { public Employee() { this.firstName = "Terry"; this.lastName = "Wingfield";

为了更好地理解多态性,我构建了一个小测试,它返回了意想不到的结果

所以我们的想法是用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();
        }
    }
使用上面的代码,我希望得到如下结果:

特里·维恩菲尔德 特里·温菲尔德 特里·温菲尔德 但是,以下内容被写入控制台:

特里·温菲尔德 无名氏 无名氏 我认为后者不起作用,因为它需要ovrride关键字

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

我希望这是足够清楚的阅读


关于,这称为方法隐藏。您只是将基类方法隐藏在派生类中。你应该得到警告,但这是完全合法的。有关更多信息,请参阅。您可能还想看看问题

这称为方法隐藏。您只是将基类方法隐藏在派生类中。你应该得到警告,但这是完全合法的。有关更多信息,请参阅。您可能还想看看问题

您显示的代码中没有多态性

将其更改为:

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。

显示的代码中没有多态性

将其更改为:

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。

对于多态行为,必须在PartTimeEmployee和FullTimeEmployee中重写这些方法。您在那里做的是将方法隐藏在基类中

        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();
        }
    }

对于多态行为,必须重写PartTimeEmployee和FullTimeEmployee中的那些方法。您在那里做的是将方法隐藏在基类中

        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();
        }
    }

使用C,您可以使用new关键字重写基类的方法。如果省略此关键字,编译器将编译源代码,就像它存在一样。 所以我想问题是:新的和覆盖的区别是什么?这是一个很大的区别

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

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


我希望我已经说得够清楚了。

使用C,您可以使用new关键字重写基类的方法。如果省略此关键字,编译器将编译源代码,就像它存在一样。 所以我想问题是:新的和覆盖的区别是什么?这是一个很大的区别

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

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

我希望我已经说得够清楚了。

这是因为

子类中的writeName将版本隐藏在基类中,您应该看到编译器警告。如果您将这三个版本全部转换为Employee,您应该会看到第一个结果。@jlRise非常感谢您。这是因为子类中的writeName将版本隐藏在基类中,您应该看到编译器警告。如果你把这三个问题都交给员工,你应该会看到第一个结果。@jlris非常感谢你。这并不能回答他的问题。他问了关于方法实现的多态性,以及为什么在他不使用覆盖的情况下调用基类方法的实现。@Alan方法隐藏确实解释了他看到的行为。他的问题是,为什么他不使用覆盖就不能得到基类方法的实现。正确的答案是,因为他没有使用对基类类型的引用。他正试图测试使用虚拟方法与不使用虚拟方法之间的区别。通过使用基类型的变量,他无法证明他的错误,无论它是否是方法隐藏。@Selman22谢谢你们的评论,但这并没有回答我的问题。这当然是问题的一部分,但不是全部。尽管如此,我还是很感谢你给我的所有时间来帮助我解决这个问题。这并不能回答他的问题。他问了关于方法实现的多态性,以及为什么在他不使用覆盖的情况下调用基类方法的实现。@Alan方法隐藏确实解释了他看到的行为。他的问题是,为什么他不使用覆盖就不能得到基类方法的实现。正确的答案是,因为他没有使用对基类类型的引用。他正试图测试使用虚拟方法与不使用虚拟方法之间的区别。通过使用基类型的变量,他无法证明他的错误,无论它是否是方法隐藏。@Selman22谢谢你们的评论,但这并没有回答我的问题。这当然是问题的一部分,但不是全部。尽管如此,我还是感谢您为帮助我解决这个问题所花费的所有时间。我看到您在实例化子类时添加了Virtual/Override关键字,但没有提到引用基类。感谢您的时间。我看到您在实例化子类时添加了Virtual/Override关键字,但没有提到引用基类。谢谢您的时间。很好的信息性评论,但可能与主题有关。我知道发生了什么,应该输出什么,但是代码中有一个错误。仍然是一个伟大的评论!将有助于未来的读者。谢谢。很好的信息性评论,但可能与主题有关。我知道发生了什么,应该输出什么,但是代码中有一个错误。仍然是一个伟大的评论!将有助于未来的读者。谢谢。考虑到您提供的代码和答案,我会将此标记为已回答。如果我可以问的话,是为了帮助未来的读者。为什么需要引用基类来实例化多态行为的子类?谢谢,谢谢。这是一个很好的信息更新,可以与您的答案一起使用。考虑到您在答案中提供了代码,我会将此标记为已回答。如果我可以问的话,是为了帮助未来的读者。为什么需要引用基类来实例化多态行为的子类?谢谢,谢谢。一个伟大的信息更新,以配合您的答案。