[C#]Virtual, abstract method and class, double dispatch

this(指向自己)

 

base(指向父类)

 

函数重载,overload,继承父类的子类能够声明一个同样名称的函数。(静态绑定)

函数覆盖,override,动态绑定。

 

静态绑定

编译时所用的foo() : compile-time type

A

A

B

A

 

这是编译器在编译的时候就确定的。

 

动态绑定:

 

但是运行的时候:run-time type

A

B

B

B

 

是根据实际的情况自动选,(最后一项,实际的还是用B的foo())

 

要根据关键词virtual 和 override

所以如果父类用了sealed ,子类用了override则在编译的时候会发生错误(无法用override声明)。调用子类的该函数的时候会回到其父类的该函数。

 

当一个子类当中既有动态绑定和静态绑定的时候,优先顺序是静态绑定>动态绑定。

 

 

抽象类以及抽象方法:(默认已经是virtual了)

 

调用类的时候就不能调用抽象类了。会发生错误。

 

Visitor Pattern

 

当出现想要在父类中添加新的方法,其所有子类也要更新相应的方法,造成很大的工作量。

this指向子类,其为静态绑定,在编译的时候就决定指向什么了

 

 

 

 

Doube dispatch exemple:

 

 public abstract class Game

    {

        public static int Fight(Game s1, Game s2)

        {

            return s1.Fight(s2);

            //return s1.Fight(s2 as dynamic);

        }

        public abstract int Fight(Game g);

        public abstract int Fight(Paper g);

        public abstract int Fight(Rock g);

        public abstract int Fight(Scissor g);

    }

 

    public class Paper : Game

    {

        public override int Fight(Game g)

        {

            return -g.Fight(this);

        }

        public override int Fight(Paper g) { return 0; }

        public override int Fight(Rock g) { return 1; }

        public override int Fight(Scissor g) { return -1; }

 

    }

    public class Rock : Game

    {

        public override int Fight(Game g)

        {

            return -g.Fight(this);

        }

        public override int Fight(Paper g) { return -1; }

        public override int Fight(Rock g) { return 0; }

        public override int Fight(Scissor g) { return 1; }

    }

    public class Scissor : Game

    {

        public override int Fight(Game g)

        {

            return -g.Fight(this);

        }

        public override int Fight(Paper g) { return 1; }

        public override int Fight(Rock g) { return -1; }

        public override int Fight(Scissor g) { return 0; }

    }

 

 class Program

    {

        static void Main(string[] args)

        {

            //Service parking = new Parking();

            //Console.WriteLine(parking.Fee(2));

            Game p = new Paper(),

                 s = new Scissor(),

                 r = new Rock();

            Console.WriteLine("P vs P:" + p.Fight(p).ToString());

            Console.WriteLine("P vs R:" + p.Fight(r).ToString());

            Console.WriteLine("P vs S:" + p.Fight(s).ToString());

 

 

        }

 

    }

 

 

有一个抽象类game,抽象类本身就是虚构的,其有三个子类,剪刀、石头、布。

因此这三个子类继承了父类的方法,但是它们选择了将父类的方法进行重载(override)分别为它们自己的方法。

 

在main()中,

以p.Fight(s)来举例,首先调用了对象p,跳回到game这个class中,找到虚构函数fight() (指向了Scissor这个子类的fight(),这是动态绑定。是override)。

 

在此之后,fight(s)中的s,则是一个被传回的参数,这个参数的类型则已经在main()函数的开头被定义,是Game类型的,于是乎这是一个静态绑定,在编译的时候就已经决定了。

 

于是调用了p这个子类中的以Game为参数类型的Fight()函数,返回了return -g.Fight(this); 首先抛去这个符号不看。

g.Fight(this);

 

g指的是传入的s这个game类型的参数,跳到了Scissor这个子类当中,调用了Scissor中fight()这个方法。但是我们注意到Fight()这个方法有很多,区别是里头的参数不同,那么这个方法的参数是this,我们知道this此时指向的是Paper, this指的就是“这个”,this所在的这个类。

于是g.Fight(this)这个方法最后的结果是S vs P, 而我们要的结果是P vs S, 所以要在前面加上一个负号。

即:

return -g.Fight(this);

 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.