virtual、abstract、override与多态

版权声明:https://blog.csdn.net/u013826918 https://blog.csdn.net/u013826918/article/details/81057761

abstract与override

using System;

public class Test
{   
    public static void Main()
    {
        Animal dog = new Dog("dog");
        Animal cat = new Cat("cat");
        dog.Shout();
        cat.Shout();    
    }
}

abstract class Animal
{
    public Animal(string name){this.name = name;}
    public string name = "Animal";
    public abstract void Shout();

}
 class Dog : Animal
{
    public Dog(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Dog 汪!");
    }
}
 class Cat : Animal
{
    public Cat(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Cat 喵!");
    }
}

输出结果为:

Dog!
Cat!

理解:

  • 父类的引用指向子类的实例,若调用其父类方法且该方法在子类中被重写,则实际调用的是子类中重写过的方法
  • 因为抽象类中的Shout方法是抽象方法,不能有方法体,不可能调用父类Animal中的Shout方法,所以很好理解。

其他补充:

  1. 抽象类可以有构造函数,虽然抽象类不可以实例化,但是可用于为其派生类在实例化之前进行一些公共的初始化操作(赋值字段、执行一些公共逻辑等)
  2. 在本例中,需要为Animal的派生类Dog、Cat实现构造函数,因为在Main函数中new操作符之后的派生类构造函数需要一个string参数。

virtual与override

using System;

public class Test
{   
    public static void Main()
    {
        Animal dog = new Dog("dog");
        Animal cat = new Cat("cat");
        dog.Shout();
        cat.Shout(); 

        Animal animal = new Animal("animal"); 
        Dog dog2 = new Dog("dog2");   
        animal.Shout();
        dog2.Shout(); 
    }
}

class Animal
{
    public Animal(string name){this.name = name;}
    public string name = "Animal";
    public virtual void Shout()
    {Console.WriteLine("Animal.Shout()");}
}
 class Dog : Animal
{
    public Dog(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Dog 汪!");
    }
}
 class Cat : Animal
{
    public Cat(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Cat 喵!");
    }
}

输出结果为:

Dog!
Cat!
Animal.Shout()
Dog!

理解:

  • 同abstract,只是父类Animal不再是抽象类,因此Animal类可以实例化。

多次override,例子一

using System;

public class Test
{   
    public static void Main()
    {
        Animal dog = new Dog("dog");
        Animal cat = new Cat("cat");
        dog.Shout();
        cat.Shout();    
        Animal bigDog = new BigDog("BigDog");
        bigDog.Shout();
    }
}

class Animal
{
    public Animal(string name){this.name = name;}
    public string name = "Animal";
    public virtual void Shout()
    {Console.WriteLine("Animal.Shout()");}
}
 class Dog : Animal
{
    public Dog(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Dog 汪!");
    }
}
 class Cat : Animal
{
    public Cat(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Cat 喵!");
    }
}
class BigDog : Dog
{
    public BigDog(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("BigDog 汪!");
    }
}

输出

Dog!
Cat!
BigDog!

理解

  • 同abstract,因此Animal bigDog = new BigDog(“BigDog”); bigDog.Shout();调用的是BigDog类中的Shout()方法。
  • 如果子类中的该方法被override,则子类的子类中的该方法不能被隐藏,要么被override重写,要么不写。

多次override例子二

using System;

public class Test
{   
    public static void Main()
    {
        Animal dog = new BigBigDog("BigBigDog");
        dog.Shout();
        Animal bigdog = new BigDog("bigdog");
        bigdog.Shout();

        Console.WriteLine("----------");

        BigDog dog2 = new BigBigDog("BigBigDog");
        dog2.Shout();
        BigDog bigdog2 = new BigDog("bigdog");
        bigdog2.Shout();
    }
}

class Animal
{
    public Animal(string name){this.name = name;}
    public string name = "Animal";
    public virtual void Shout()
    {Console.WriteLine("Animal.Shout()");}
}
 class Dog : Animal
{
    public Dog(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Dog 汪!");
    }
}
class BigDog : Dog
{
    public BigDog(string name) : base(name){}

}
class BigBigDog : BigDog
{
    public BigBigDog(string name) : base(name){}
}

输出

Dog 汪!
Dog 汪!
----------
Dog 汪!
Dog 汪!

理解

  • BigBigDog没有Shout方法,向父类一层层找,找到基类Animal的Shout方法,发现是virtual虚方法,再向上找override重写后的方法所在的类(直到BigBigDog这层为止),结果找到了Dog类中被重写的Shout,并且再向上找Dog类与BigBigDog之间,没有对应的重写后的方法,于是最终调用的是Dog.Shout()方法。
  • BigDog dog2 = new BigBigDog(“BigBigDog”);实际上dog2所在类BigBigDog中没有Shout方法,向父类找到基类Animal的Shout方法,其他同上。
  • BigDog bigdog2 = new BigDog(“bigdog”);同上。

多态

using System;

public class Test
{   
    public static void Main()
    {
        Animal dog = new Dog("dog");
        Animal cat = new Cat("cat");
        MyShout(dog);
        MyShout(cat);


    }
    static void MyShout(Animal animal)
    {
        animal.Shout();
    }
}

abstract class Animal
{
    public Animal(string name){this.name = name;}
    public string name = "Animal";
    public abstract void Shout();

}
 class Dog : Animal
{
    public Dog(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Dog 汪!");
    }
}
 class Cat : Animal
{
    public Cat(string name) : base(name){}
    public override void Shout()
    {
        Console.WriteLine("Cat 喵!");
    }
}

理解

  • 与abstract例子一很类似,MyShout方法只知道参数是Animal,并不知道具体被传入的是什么动物(猫还是狗),但是却能够运作良好,传入狗和猫时分别调用了狗和猫的Shout方法。

补充

  • 应该避免从实体类Animal继承,而是将Animal定义为抽象类并继承,因为实例化Animal是无意义的(不知道具体是什么动物所以不知道怎么Shout),我们只需要利用多态特性。
  • 如果Animal是抽象类,那么就可以避免传入Animal类的实例(因为抽象类不可以被实例化,想创建一个Animal类实例作为MyShout的参数根本无法通过编译)。

思考一:想想以下代码的输出是什么?

using System;

public class Test
{
    public static void Main()
    {
        var b = new B(12);
        var a = b as A;
        Console.WriteLine("---------------");
        Console.WriteLine("a.GetA={0},a.GetAA={1}  b.GetA()={2},b.GetAA()={3}", a.GetA(), a.GetAA(), b.GetA(), b.GetAA());
        Console.WriteLine("---------------");
        var a1 = new A(10);
        Console.WriteLine("a1.GetA()={0}", a1.GetA());
    }
}

public class A
{
    protected int m_a;
    public A(int _a) { m_a = _a; Console.WriteLine("constructor A, m_a={0}", m_a);}
    public virtual int GetA()
    {
        Console.WriteLine("call a.GetA, return this.m_a={0}", m_a);
        return m_a;
    }
    public int GetAA()
    {
        Console.WriteLine("call a.GetAA, return this.m_a={0}", m_a);
        return m_a;
    }
}
public class B : A
{
    //思考二:将下一行代码注释后,输出是什么
    private int m_a;
    public B(int _a) : base(_a) { m_a+=_a-1; Console.WriteLine("constructor B, private b.m_a={0}", m_a);}
    public override int GetA()
    {
        Console.WriteLine("call b.GetA, return this.m_a={0}", m_a);
        return m_a;
    }
}

参考链接:
https://www.cnblogs.com/joeylee/p/3631246.html

猜你喜欢

转载自blog.csdn.net/u013826918/article/details/81057761