zoukankan      html  css  js  c++  java
  • 浅谈重写、重载、继承、多态

    一、重写

      通过为声明的方法提供新的实现,派生类可以重写基类的方法。并且基类中的这个方法必须标记为虚方法(virtual),Java和C#之间的一个重要区别在于,Java方法在默认情况下标记为虚方法,而在C#中,必须使用virtual修饰符才能将方法显式标记为虚方法。可以采用大致相同的方式重写属性访问器以及方法。

    • 不能重写非虚方法或静态方法。重写的基方法必须是 virtual、abstract 或 override 的。为什么 override 也可以重写呢?因为基类中的 override实际上是对基类的基类进行的重写,由于继承可传递,所以也可以对基类中 override 的方法进行重写。
    • override声明不能更改virtual方法的可访问性。override 方法和 virtual 方法必须具有相同的访问级别修饰符。
    • 不能使用修饰符 new、static、virtual 或 abstract 来修改 override 方法。
    • 重写属性声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且被重写的属性必须是 virtual、abstract 或 override 的。
    • 可以在重写方法的中用base调用基类的方法

    例子如下:本文所有例子是一个关于动物的类、抽象类、接口的部分代码)

        public class Dog : Animals,IAction {
            public Dog()
            {
            }
            public Dog(string name)
            {
                _name = name;
            }
            public override string Name
            {
                get
                {
                    return _name;
                }
            }
            /*****省略部分代码****/
            public virtual void FurColor(){
                Console.WriteLine("Performing base class fur color");
            }
        }
    
        class Pomeranian:Dog {
            public Pomeranian()
            {
            }
            public override void FurColor()
            {
                Console.WriteLine("Pomeranian's fur color is white.");
                //base.FurColor();
            }
        }
    
        class Program {
            static void Main(string[] args)
            {
                Pomeranian dog1 = new Pomeranian();
                dog1.FurColor();//调用new隐藏后的方法
                Console.WriteLine();
             }
         }
    涉及到的抽象类Animals
    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ClassTest {
        public abstract class Animals
        {
            protected string _name;
            
            //声明抽象属性
            public abstract string Name 
            { 
                get; 
            }
            //声明抽象方法
            public abstract void Show();
            //实现虚方法
            public virtual void MakeVoice()
            {
                Console.WriteLine("All animals can make voice.");
            }
            //实现一般的方法
            public void Sleep()
            {
                Console.WriteLine("All the animals need to sleep.");
            }
        }
    }

    设计到的接口IAction

    View Code
    【注】方法隐藏
          无论基类中的方法是否用了virtual关键字,继承类中都可以用new关键字(如果不用new的话,不会产生错误,但会生成一个编译警告)将基类中的方法隐藏,重写就是原来的(基类中)已经不存在了,而隐藏是原来的还存在。所以当让基类的对象的引用直接指向继承类的对象时(多态性),调用该方法则是调用的基类的方法。
    例子:
    在Animals中有个MakeVoice()的虚方法,我们将它在子类中通过用override重写和new隐藏看看实现的效果
    新建一个Duck类,继承于Animals,然后重写这个MakeVoive()
    public class Duck : Animals, IAction {
            public Duck(string name)
            {
                this._name = name;
            }
            //重写抽象属性
            public override string Name
            {
                get
                {
                    return _name;
                }
            }
            /******省略部分代码******/
            //重写虚方法
            public override void MakeVoice()
            {
                Console.WriteLine("I am a duck,ga....ga....");
            }
        }

    然后在Dog类中添加new隐藏方法

    public new void MakeVoice()//用new关键字将虚方法隐藏
    {
           base.MakeVoice();//调用基类方法
           Console.WriteLine("   I'am a dog,wang...wang...");
    }

    在Main函数中写代码调用

    /**省略了与这两个无关的代码*
    *Duck重写了Makevoice(),只能实现子类中的方法
    *Dog隐藏了Makevoice(),但是父类还可以调用它的代码
    */
    Animals duck=new Duck("Duck");
    duck.MakeVoice();//调用override重写后的虚方法
    
    Animals dog=new Dog("Dog");
    dog.MakeVoice();//直接调用基类虚方法(new 关键字方法隐藏)
    
    Dog dog1 = new Dog("dog1");
    dog1.MakeVoice();//调用new隐藏后的方法

    结果如下:

    二、重载( overloading )

    C#中同一个类不可以有两个相同的方法(方法名、参数类型、参数个数和参数位置都 相同)。但可以有方法名相同,参数不同(参数类型、参数个数和参数位置不相同)的方法。这 种相同的方法名,参数不同的方法称为重载。

      决定方法是否构成重载有以下几个条件:

      ◆ 在同一个类中;

      ◆ 方法名相同;

      ◆ 参数列表不同。

    例子:我们创建一个机器狗BattleRavage,让它可以计算加法

        class BattleRavage:Dog {
            public BattleRavage():base("brDog")
            {    
            }
    
            //这只狗有计算的能力,实现重载功能
            public string add()
            {
                return "I'm ready!";
            }
            public double add(double numberOne, double numberTwo)
            {
                return numberOne + numberTwo;
            }
            public double add(double numberOne, double numberTwo, double numberThree)
            {
                return numberOne + numberTwo + numberThree;
            }
            public new void Sleep()
            {
                Console.WriteLine("I don't need to go to");
            }
        }

    Main中实现:

    //实现重载add()
    BattleRavage brDog = new BattleRavage();
    brDog.Sleep();//调用new方法
    Console.WriteLine("这条狗能做算术,很厉害!");
    string dogReady = brDog.add();
    double result1 = brDog.add(2.2, 5.5);
    double result2 = brDog.add(2, 4, 3);
    Console.WriteLine(dogReady);
    Console.WriteLine("2.2+5.5=" + result1.ToString());
    Console.WriteLine("2+4+3=" + result2.ToString());
    Console.WriteLine();

    运行结果:

    三、继承

          为了提高软件模块的可复用性和可扩充性,以便提高软件的开发效率,我们总是希望能够利用前人或自己以前的开发成果,同时又希望在自己的开发过程中能够有足够的灵活性,不拘泥于复用的模块。

          继承就是子类获得父类的成员和使用父类的方法。

        C#中的继承符合下列规则:

        1、继承是可传递的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。Object 类作为所有类的基类。

        2、派生类应当是对基类的扩展。派生类可以添加新的成员,但不能除去已经继承的成员的定义。

        3、构造函数和析构函数不能被继承。除此以外的其它成员,不论对它们定义了怎样的访问方式,都能被继承。基类中成员的访问方式只能决定派生类能否访问它们。

        4、派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。但这并不因为这派生类删除了这些成员,只是不能再访问这些成员。

        5、类可以定义虚方法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态性。

        6、派生类只能从一个类中继承,可以通过接吕实现多重继承。  

     

    四、多态

        多态则是为了避免在父类里大量重载引起代码臃肿且难于维护。
        网上看到一个有趣的说法是:继承是子类使用父类的方法,而多态则是父类使用子类的方法。 

      多态性常被视为自封装和继承之后,面向对象的编程的第三个支柱。 Polymorphism(多态性)是一个希腊词,指“多种形态”,多态性具有两个截然不同的方面:

    1. 在运行时,在方法参数和集合或数组等位置,派生类的对象可以作为基类的对象处理。 发生此情况时,该对象的声明类型不再与运行时类型相同。

    2. 基类可以定义并实现方法,派生类可以重写这些方法,即派生类提供自己的定义和实现。 在运行时,客户端代码调用该方法,CLR 查找对象的运行时类型,并调用虚方法的重写方法。 因此,您可以在源代码中调用基类的方法,但执行该方法的派生类版本。

      C#支持两种类型的多态性:

        ● 编译时的多态性

        编译时的多态性是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。

        ● 运行时的多态性

        运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中,运行时的多态性通过虚成员实现。

    编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。

     例子:在基类Dog中添加一个显示皮毛颜色的方法,然后在各子类中重写该方法,最后通过基类去调用各子类的方法

        public class Dog : Animals, IAction {
            public Dog()
            {
            }
            public Dog(string name)
            {
                _name = name;
            }
            public override string Name
            {
                get
                {
                    return _name;
                }
            }
            public virtual void FurColor(){
                Console.WriteLine("Performing base class fur color");
            }
        }
    
        class Pomeranian:Dog {
            public Pomeranian()
            {
            }
            public override void FurColor()
            {
                Console.WriteLine("Pomeranian's fur color is white.");
                //base.FurColor();
            }
        }
    
        class Labrador:Dog {
            public Labrador()
            {
            }
            public override void FurColor()
            {
                Console.WriteLine("Labrador's fur color is pale yellow.");
                //base.FurColor();
            }
        }
    
        class Husky:Dog {
            public Husky()
            {    
            }
            public override void FurColor()
            {
                Console.WriteLine("Husky' fur color is black and white mixed color.");
                base.FurColor();
            }
        }
    
        class Program {
            static void Main(string[] args)
            {
                  //实现多态,调用基类的方法,但执行该方法的派生类版本
                List<Dog> dogs = new List<Dog>();
                dogs.Add(new Husky());
                dogs.Add(new Labrador());
                dogs.Add(new Pomeranian());
                foreach (Dog s in dogs)
                {
                    s.FurColor();
                }
            }
        }

    运行结果:

     

    总结:

      多态性通过继承、重写、虚方法等来实现,重写就是在子类中写出和基类中不同的方法(该方法可以为virtual、abstract 或 override)实现(方法名,参数,返回值都一样),重载允许我们用相同的方法名实现不同的操作,继承则是子类获得父类的成员和使用父类的方法。

     

    参考资料:

    http://www.cnblogs.com/hliq/archive/2011/04/06/2087191.html

    http://msdn.microsoft.com/zh-cn/library/ms173152.aspx

  • 相关阅读:
    python学习第18天----属性、类方法、静态方法
    面试总结
    JAVA面试题整理
    Docker-基础
    Shell
    MYSQL
    logstash的使用(ELK)
    (ELK)FileBeat的使用
    Zookeeper的介绍和单机、集群搭建
    Elaticsearch7.7.0的安装(ELK)
  • 原文地址:https://www.cnblogs.com/huangbx/p/2637206.html
Copyright © 2011-2022 走看看