为什么在我的派生类中调用方法会调用基类方法? [英] Why does calling a method in my derived class call the base class method?

查看:38
本文介绍了为什么在我的派生类中调用方法会调用基类方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这个代码:

class Program
{
    static void Main(string[] args)
    {
        Person person = new Teacher();
        person.ShowInfo();
        Console.ReadLine();
    }
}

public class Person
{
    public void ShowInfo()
    {
        Console.WriteLine("I am Person");
    }
}
public class Teacher : Person
{
    public new void ShowInfo()
    {
        Console.WriteLine("I am Teacher");
    }
}

当我运行这段代码时,输​​出如下:

When I run this code, the following is outputted:

我是人

但是,您可以看到它是Teacher 的实例,而不是Person 的实例.为什么代码会这样做?

However, you can see that it is an instance of Teacher, not of Person. Why does the code do that?

推荐答案

newvirtual/override 是有区别的.

There's a difference between new and virtual/override.

您可以想象,一个类在实例化时只不过是一个指针表,指向其方法的实际实现.下图应该可以很好地形象化:

You can imagine, that a class, when instantiated, is nothing more than a table of pointers, pointing to the actual implementation of its methods. The following image should visualize this pretty well:

现在有不同的方法,可以定义一个方法.当它与继承一起使用时,每个行为都不同.标准方式始终如上图所示.如果你想改变这种行为,你可以在你的方法中附加不同的关键字.

Now there are different ways, a method can be defined. Each behaves different when it is used with inheritance. The standard way always works like the image above illustrates. If you want to change this behavior, you can attach different keywords to your method.

第一个是abstract.abstract 方法只是指向无处:

The first one is abstract. abstract methods simply point to nowhere:

如果您的类包含抽象成员,还需要将其标记为abstract,否则编译器将不会编译您的应用程序.您不能创建 abstract 类的实例,但可以从它们继承并创建继承类的实例,并使用基类定义访问它们.在您的示例中,这看起来像:

If your class contains abstract members, it also needs to be marked as abstract, otherwise the compiler will not compile your application. You cannot create instances of abstract classes, but you can inherit from them and create instances of your inherited classes and access them using the base class definition. In your example this would look like:

public abstract class Person
{
    public abstract void ShowInfo();
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a teacher!");
    }
}

public class Student : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a student!");
    }
}

如果被调用,ShowInfo 的行为会因实现而异:

If called, the behavior of ShowInfo varies, based on the implementation:

Person person = new Teacher();
person.ShowInfo();    // Shows 'I am a teacher!'

person = new Student();
person.ShowInfo();    // Shows 'I am a student!'

Students 和 Teachers 都是 Persons,但是当他们被要求提示有关他们自己的信息时,他们的行为有所不同.然而,让他们提示他们信息的方式是一样的:使用Person类接口.

Both, Students and Teachers are Persons, but they behave different when they are asked to prompt information about themselves. However, the way to ask them to prompt their information, is the same: Using the Person class interface.

那么,当您从 Person 继承时,幕后会发生什么?在实现 ShowInfo 时,指针不再指向 nowhere,它现在指向实际的实现!创建Student实例时,它指向StudentShowInfo:

So what happens behind the scenes, when you inherit from Person? When implementing ShowInfo, the pointer is not pointing to nowhere any longer, it now points to the actual implementation! When creating a Student instance, it points to Students ShowInfo:

第二种方法是使用virtual方法.行为是相同的,除了您在基类中提供可选 默认实现.可以实例化具有 virtual 成员的类,但是继承的类可以提供不同的实现.以下是您的代码实际工作时的样子:

The second way is to use virtual methods. The behavior is the same, except you are providing an optional default implementation in your base class. Classes with virtual members can be instanciated, however inherited classes can provide different implementations. Here's what your code should actually look like to work:

public class Person
{
    public virtual void ShowInfo()
    {
        Console.WriteLine("I am a person!");
    }
}

public class Teacher : Person
{
    public override void ShowInfo()
    {
        Console.WriteLine("I am a teacher!");
    }
}

关键区别在于,基本成员 Person.ShowInfo 不再指向 nowhere.这也是为什么您可以创建 Person 的实例的原因(因此它不再需要标记为 abstract):

The key difference is, that the base member Person.ShowInfo isn't pointing to nowhere any longer. This is also the reason, why you can create instances of Person (and thus it does not need to be marked as abstract any longer):

您应该注意到,目前这与第一张图片并没有什么不同.这是因为 virtual 方法指向标准方式"的实现.使用virtual,你可以告诉Persons,他们可以(不是必须)为提供不同的实现>显示信息.如果您提供不同的实现(使用 override),就像我为上面的 Teacher 所做的那样,图像看起来与 abstract 相同.想象一下,我们没有为 Students 提供自定义实现:

You should notice, that this doesn't look different from the first image for now. This is because the virtual method is pointing to an implementation "the standard way". Using virtual, you can tell Persons, that they can (not must) provide a different implementation for ShowInfo. If you provide a different implementation (using override), like I did for the Teacher above, the image would look the same as for abstract. Imagine, we did not provide a custom implementation for Students:

public class Student : Person
{
}

代码会这样调用:

Person person = new Teacher();
person.ShowInfo();    // Shows 'I am a teacher!'

person = new Student();
person.ShowInfo();    // Shows 'I am a person!'

Student 的图像如下所示:

new 更像是一个解决这个问题的技巧.您可以在通用类中提供方法,这些方法与基类/接口中的方法具有相同的名称.两者都指向自己的自定义实现:

new is more a hack around this. You can provide methods in generalized classes, that have the same names as methods in the base class/interface. Both point to their own, custom implementation:

实现看起来像你提供的那个.根据您访问方法的方式,行为会有所不同:

The implementation looks like the one, you provided. The behavior differs, based on the way you access the method:

Teacher teacher = new Teacher();
Person person = (Person)teacher;

teacher.ShowInfo();    // Prints 'I am a teacher!'
person.ShowInfo();     // Prints 'I am a person!'

这种行为可能是需要的,但就您而言,这是一种误导.

This behavior can be wanted, but in your case it is misleading.

我希望这能让你更清楚地理解!

I hope this makes things clearer to understand for you!

这篇关于为什么在我的派生类中调用方法会调用基类方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆