浅谈重写、重载、继承、多态

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

一、重写

  通过为声明的方法提供新的实现,派生类可以重写基类的方法。并且基类中的这个方法必须标记为虚方法(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

 

 

目录
相关文章
|
7月前
|
C#
C# 继承类中(父类与子类)构造函数的调用顺序
C# 继承类中(父类与子类)构造函数的调用顺序
|
10月前
类的继承和重写方法
类的继承和重写方法
50 0
|
10月前
|
编译器 定位技术
在父类的构造函数中调用虚函数为什么不能实现多态
在父类的构造函数中调用虚函数为什么不能实现多态
74 0
|
开发者 Python
子类重写父类方法|学习笔记
快速学习子类重写父类方法,先来介绍子类重写父类方法。多态其实就是一种子类重写父类的方法。
144 0
|
Java C++
C++继承与派生解析(继承、重载/转换运算符、多重继承、多态、虚函数/纯虚函数、抽象类)
C++继承与派生解析(继承、重载/转换运算符、多重继承、多态、虚函数/纯虚函数、抽象类)
159 0
|
Java 编译器
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(2)
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(2)
119 0
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(2)
|
Java 编译器 数据库
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(1)
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(1)
90 0
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(1)
|
Java 程序员 C++
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(3)
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(3)
174 0
java面向对象编程_包_继承_多态_重载和重写_抽象类_接口_this和super(3)