虚函数C# [英] Virtual Functions C#

查看:95
本文介绍了虚函数C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我了解什么是虚函数.但是我不明白的是它们在内部如何工作?

I understand what a virtual function is. But what I don't get is how do they work internally?

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

上面的输出给出:

Eat like a Human
Eat undefined

在上面的代码中,_animal是动物类型,它引用人类对象或狗对象. 这是什么意思?我知道在_animal内存中包含一个将指向人"或狗"对象的地址.它如何决定调用哪个函数.在第一种情况下,我重写并因此调用了子级的实现,但是在第二种情况下,我使用了new并因此调用了父级的实现.您能给我解释一下幕后情况吗?

In the above code _animal is of type Animal which references a Human object or Dog object. What does this mean? I understand in the memory _animal contains an address which will point to Human or Dog object. How does it decide which function to invoke. In the first case I override and hence child's implementation is called, but in second case I use new and hence the parent's implementation is called. Can you please explain me what happens under the hood?

先谢谢了 尼克

推荐答案

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

It works like this. Imagine the compiler rewrote your classes into this:

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

现在考虑以下电话:

Animal animal;
Dog dog;
animal = new Human();
animal.Eat();
animal = new Animal();
animal.Eat();
dog = new Dog();
dog.Eat();
animal = dog;
animal.Eat();

编译器的原因如下:如果接收方的类型为Animal,则Eat的调用必须为animal.VTable.AnimalEat.如果接收方的类型为Dog,则呼叫必须为DogEat.因此,编译器将它们写为:

The compiler reasons as follows: If the type of the receiver is Animal then the call to Eat must be to animal.VTable.AnimalEat. If the type of the receiver is Dog then the call must be to DogEat. So the compiler writes these as:

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

这是确切的工作方式.编译器会在后台为您生成vtable,并在编译时根据重载解析规则决定是否通过vtable调用.

That is exactly how it works. The compiler generates vtables for you behind the scenes, and decides at compile time whether to call through the vtable or not based on the rules of overload resolution.

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

The vtables are set up by the memory allocator when the object is created. (My sketch is a lie in this regard, since the vtable is set up before the ctor is called, not after.)

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

The "this" of a virtual method is actually secretly passed as an invisible formal parameter to the method.

有道理吗?

这篇关于虚函数C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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