继承 多态的理解

当父类允许子类重写某一方法时,需用virtual修饰,但并不要求子类必须重写这个方法。

在子类重写父类的方法过程中,如果子类使用new修饰Eat()方法

public class Animal
    {
        public virtual void Eat()
        {
            Console.WriteLine("Animal eat");
        }
    }

    public class Cat : Animal
    {
        public new void Eat()
        {
            Console.WriteLine("Cat eat");
        }
    }

    class Tester
    {
        static void Main(string[] args)
        {
            Animal a = new Animal();
            a.Eat();

            Animal ac = new Cat();
            ac.Eat();

            Cat c = new Cat();
            c.Eat();
        }
    }

运行结果为:

Animal eat…

Animal eat…

Cat eat…

多态的定义:

同一个事件发生在不同的对象上会产生不同的结果
通过继承实现的不同对象调用相同的方法,表现出不同的行为,称之为多态

那么并没有实现多态,并没有因为定义的Animal是Cat而使用Cat的Eat()方法。这是因为使用new修饰,编译器在创建子类对象时,内存的父类和子类都有Eat()方法,根据就近法则,定义的是Animal,则直接调用Animal的Eat()。如果定义的是Cat,则调用Cat的Eat()。

Animal ac = new Cat();其实是限制了ac只能访问Animal类的成员

这样做有一个明显的限制 ac 对象只能访问基类中的成员不能访问派生类中的成员
这就是为什么C#完全面向对象的原因,因为C#中所有的东西都继承自System.Object,任何东西都能赋给一个object变量

而如果使用overrider修饰的方法,编译器在创建子类对象时,虽然也copy了一份父类的方法,但是子类的Eat()已经覆盖了父类的Eat(),所以调用的是子类的Eat()。

Bird bird=new Swallow(); 这种情况下bird.Show();应该调用那个方法?有两个原则,是.NET专门解决这个问题。如下: 1) 关注对象创建原则:调用子类还是父类的方法,取决于创建的对象是子类对象还是父类对象,而不是它的引用类型。 2) 执行就近原则:对于同名的方法或者字段,编译器是按照顺序查找来引用的,也就是首先访问距离它最近的字段或者方法。 注意:ovveride重写父类的方法是在地址列表中覆盖了父类的方法,所以如果最终运行的是子类的对象,则执行了子类中的方法(因为覆盖了父类方法的地址,第一个原则)。 new是在子类中定义了与父类同名的方法,要隐藏父类的同名方法,在编译器的时候其实是为父类和子类的两个方法分配了地址,只不过父类方法排在前面,而子类方法排在后面,就近原则根据定义的类型来决定,这样根据就近原则,如果定义的对象类型为父类,则就近找到父类的方法执行,而如果定义在子类的类型,则就近找到子类的方法执行。
子类只拷贝父类中的方法,如果父类中没有对应的方法,才会向上查找,直至找到object类。

public class Animal
    {
        public virtual void Eat()
        {
            Console.WriteLine("Animal eat");
        }
    }

    public class Cat : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("Cat eat");
        }
    }

    public class Dog : Animal
    {
        public override void Eat()
        {
            Console.WriteLine("Dog eat");
        }
    }

    class Tester
    {
        static void Main(string[] args)
        {
            Animal[] animals = new Animal[3];

            animals[0] = new Animal();
            animals[1] = new Cat();
            animals[2] = new Dog();

            for (int i = 0; i < 3; i++)
            {
                animals[i].Eat();
            }
        }
    }

输出如下:

Animal eat…

Cat eat…

Dog eat…

综上,virtual与override的结合,这才是实现了多态。override是覆盖,new是共存。

当派生类Cat的Eat()方法使用new修饰时,Cat的对象转换为Animal对象后,调用的是Animal类中的Eat()方法。其实可以理解为,使用new关键字后,使得Cat中的Eat()方法和Animal中的Eat()方法成为毫不相关的两个方法,只是它们的名字碰巧相同而已。所以, Animal类中的Eat()方法不管用还是不用virtual修饰,也不管访问权限如何,或者是没有,都不会对Cat的Eat()方法产生什么影响(只是因为使用了new关键字,如果Cat类没用从Animal类继承Eat()方法,编译器会输出警告)。

继承的拓展

继承是可用传递的 , 子类是对父类的扩展 , 必须继承父类的方法,同时在子类中添加新方法。 子类可用调用父类的公用方法和字段 , 而父类不能调用子类的成员。 子类不仅继承了父类的共有成员 , 同时也继承了父类的私有成员 , 只是在子类中不能被访问。
继承的三个关键字: abstract 抽象。用来限定类时,类中的方法不能有方法实体;用来限定方法时,同样也不能有方法实体,并且在子类中必须完成方法实体,除非子类继续使用抽象方法。
virtual 用来指示类中的方法可以被子类的同名方法覆盖或者共存,覆盖时,子类中使用override关键字;
共存时,使用new 关键字。new 在子类方法中的用法是指子类中与父类存在的同名方法在方法列表敏感词存,并不覆盖父类的方法,这就达到了多态机制下并非一味覆盖的效果。

对C#继承的理解----菜鸟葫芦娃

C#中的多态----- 唔愛吃蘋果

请简述private,public,protected,internal的区别
A:
public:对任何类和成员都公开,无限制访问
private:仅对该类公开
protected:对该类和其派生类公开
internal:只能在包含该类的程序集中访问该类

override和overload的区别
A:
override表示重写,用于继承类对基类中虚成员的实现
overload表示重载,用于同一个类中同名方法不同参数(包括类型不同或个数不同)的实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值