虚函数C#

Nis*_*ant 3 c# methods virtual

我理解虚函数是什么.但我没有得到的是他们如何在内部工作?

class Animal
{
    virtual string Eat()
    {
        return @"Eat undefined";
    }
}

class Human : Animal
{
    override string Eat()
    {
         return @"Eat like a Human";
    }
}


class Dog : Animal
{
    new string Eat()
    {
         return @"Eat like a Dog";
    }
}

static void Main()
{
    Animal _animal = new Human();
    Console.WriteLine(_animal.Eat());
    _animal = new Dog();
    Console.WriteLine(_animal.Eat());
}
Run Code Online (Sandbox Code Playgroud)

上面的输出给出:

Eat like a Human
Eat undefined
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,_animal是Animal类型,它引用了Human对象或Dog对象.这是什么意思?我理解在内存中_animal包含一个指向Human或Dog对象的地址.它如何决定调用哪个函数.在第一种情况下,我覆盖,因此调用了子的实现,但在第二种情况下,我使用new,因此调用了父实现.能告诉我发动机罩下发生了什么吗?

在此先感谢尼克

Eri*_*ert 17

它的工作原理如下.想象一下,编译器将您的类重写为:

class VTable
{
    public VTable(Func<Animal, string> eat)
    {
        this.AnimalEat = eat;
    }
    public readonly Func<Animal, string> AnimalEat;
}

class Animal
{
    private static AnimalVTable = new VTable(Animal.AnimalEat);
    private static string AnimalEat(Animal _this)
    { 
        return "undefined"; 
    }
    public VTable VTable;
    public static Animal CreateAnimal() 
    { 
        return new Animal() 
            { VTable = AnimalVTable }; 
    }
}

class Human : Animal
{
    private static HumanVTable = new VTable(Human.HumanEat); 
    private static string HumanEat(Animal _this)
    {
        return "human"; 
    }
    public static Human CreateHuman()
    {
        return new Human() 
            { VTable = HumanVTable };
    }
}

class Dog : Animal
{
    public static string DogEat(Dog _this) { return "dog"; }
    public static Dog CreateDog()
    {
        return new Dog() 
            { VTable = AnimalVTable } ;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在考虑这些电话:

Animal animal;
Dog dog;
animal = new Human();
animal.Eat();
animal = new Animal();
animal.Eat();
dog = new Dog();
dog.Eat();
animal = dog;
animal.Eat();
Run Code Online (Sandbox Code Playgroud)

编译器的原因如下:如果接收器的类型是Animal,那么对Eat的调用必须是animal.VTable.AnimalEat.如果接收器的类型是Dog,那么呼叫必须是DogEat.所以编译器将这些写为:

Animal animal;
Dog dog;
animal = Human.CreateHuman(); // sets the VTable field to HumanVTable
animal.VTable.AnimalEat(animal); // calls HumanVTable.AnimalEat
animal = Animal.CreateAnimal(); // sets the VTable field to AnimalVTable
animal.VTable.AnimalEat(animal); // calls AnimalVTable.AnimalEat
dog = Dog.CreateDog(); // sets the VTable field to AnimalVTable
Dog.DogEat(dog); // calls DogEat, obviously
animal = dog;
animal.VTable.AnimalEat(animal); // calls AnimalVTable.AnimalEat
Run Code Online (Sandbox Code Playgroud)

正是它的工作原理.编译器在后台为您生成vtables,并在编译时决定是否根据重载决策规则调用vtable.

在创建对象时,内存分配器会设置vtable.(我的草图在这方面是谎言,因为vtable是调用ctor 之前设置的,而不是之后的.)

虚拟方法的"this"实际上是作为方法的不可见形式参数秘密传递的.

合理?

  • @Eric:嗨Eric,我注意到你从高级开发人员到主要开发人员更新了你的信息.我没有参加3天的比赛,所以我假设你在周末更新了:O只是想对你的新职位/晋升表示祝贺,如果我这样说的话,你应该得到它.这也意味着什么,C#将通过你的一切?我希望如此,因为你是IMO最好的开发者之一. (7认同)
  • @Eric:如果你仍然认为自己是一名大三学生,这很有趣,我不知道你下面的人会是什么:O从我工作的地方,即使它不是一家软件公司,校长也很高兴.但我想像微软这样的软件巨头,其间的分数要多得多.无论哪种方式,能够与你们交谈都是非常宝贵的经验.期待看到你在队伍和幸福中上升. (3认同)