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方法,所以很好理解。
其他补充:
- 抽象类可以有构造函数,虽然抽象类不可以实例化,但是可用于为其派生类在实例化之前进行一些公共的初始化操作(赋值字段、执行一些公共逻辑等)
- 在本例中,需要为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;
}
}