多态性:
概念:擁有共同基類的派生類,從基類中繼承的方法,都有不同的實作方式。
多态性可以簡單地概括為”一個接口,多種方法”,它是在程式運作的過程中才決定調用的方法,多态性是面向對象程式設計的核心概念。多态使得子類的執行個體可以直接賦予基類的對象,然後直接就可以通過這個對象調用子類(派生類)的方法。
注:1、多态性主要用于實作接口重用,因為接口是程式中最耗費時間的資源,實質上設計一個接口要比設計一堆類要顯得更有效率。2、多态性在C#中主要通過虛方法和重寫方法來展現。
抽象類
抽象方法:隻有方法的聲明,而沒有具體的實作。
含有抽象方法的類,稱之為抽象類。有抽象方法的類一定是抽象類,抽象類例不一定有抽象方法。抽象類或抽象方法都用到了關鍵字:abstract
對于抽象類來說,隻能作為其他類的基類(不能建立對象),而對于派生類來說,如果派生類不是抽象類的話,哪麼要求派生類必須重寫(關鍵字override)基類的所有抽象方法。在抽象類中可以含有已經實作的方法,不能建立對象。
在派生類中使用new 隐藏基類的方法。
如果基類不是抽象類,而是含有一個具體實作方法的類,則在派生類中,通過使用new關鍵字來實作多态。
基類是虛方法(virtual),派生類重寫(override)基類的方法,注意:方法的重載的差別。
重載:同一個類中,方法的名字完全一樣,但是參數不一樣,包括:1.參數的個數不一樣,2。參數的資料類型不一樣
注:如果C#根據調用參數,沒有找到對應的方法,那麼将調用最近類型參數的方法。例:
public class TestAdd
{
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
public int Add(string a, string b)
return Convert.ToInt32(a) + Convert.ToInt32(b);
}
class Program
static void Main(string[] args)
TestAdd t = new TestAdd();
t.Add(0, 2);//調用Add(int a,int b)
t.Add(2.0, 3.0);//調用Add(double a, double b)
t.Add("2", "5");//調用Add(string a, string b)
t.Add(2, 3.0);//調用Add(double a, double b)
多态舉例:覆寫 在子類中用 new 關鍵字修飾 定義的與父類中同名的方法,叫覆寫。
覆寫不會改變父類方法的功能。
看下面示範代碼:例1、
public class BaseClass
public void Say()
Console.WriteLine("BaseClass");
public class DriveClass : BaseClass
public new void Say()//使用關鍵字new隐藏基類同名的方法
Console.WriteLine("Drive Class");
BaseClass dc = new DriveClass();//誰引用調用誰
DriveClass dd = new DriveClass();
dc.Say();
dd.Say();
}
輸出結果:
BaseClass
DriveClass
重寫:用關鍵字 virtual 修飾的方法,叫虛方法。可以在子類中用override 聲明同名的方法,這叫“重寫”。相應的沒有用virtual修飾的方法,我們叫它實方法。重寫會改變父類方法的功能。
看下面示範代碼:例2、
public virtual void Say()
public override void Say()//使用關鍵字new隐藏基類同名的方法
總結
1:不管是重寫還是覆寫都不會影響父類自身的功能(廢話,肯定的嘛,除非代碼被改)。
2:當用子類建立父類的時候,如 C1 c3 = new C2(),重寫會改變父類的功能,即調用子類的功能;而覆寫不會,仍然調用父類功能。
3:虛方法、實方法都可以被覆寫(new),抽象方法,接口 不可以。
4:抽象方法,接口,标記為virtual的方法可以被重寫(override),實方法不可以。
5:重寫使用的頻率比較高,實作多态;覆寫用的頻率比較低,用于對以前無法修改的類進行繼承的時候。
例3、通過類的多态性确定人類的說話行為
public partial class Form1 : Form
public Form1()
{ InitializeComponent();}
private void button1_Click(object sender, EventArgs e)
if (textBox1.Text == "")//判斷是否輸入了姓名
{
Console.WriteLine("請輸入姓名:");
return;
}
richTextBox1.Clear();//清空文本框内容
string strName = textBox1.Text;//記錄使用者輸入的名字
People[] people = new People[2];//聲明People類型數組
people[0] = new Chinese();//使用第一個派生類對象初始化數組的第一個元素
people[1] = new American();//使用第二個派生類對象初始化數組的第二個元素
for (int i = 0; i < people.Length; i++)//周遊指派後的數組
{//根據數組元素調用相應派生類中的重寫方法
people[i].Say(richTextBox1,strName);
}
class People//定義基類
{//定義一個虛方法,用來表示人的說話行為
public virtual void Say(RichTextBox rtbox, string name)
rtbox.Text += name;//輸出人的名字
class Chinese : People//定義派生類,繼承于People類
{//重寫基類中的虛方法
public override void Say(RichTextBox rtbox, string name)
base.Say(rtbox, name + "說漢語!\n");
class American : People//定義派生類,繼承于People類
public override void Say(RichTextBox rtbox, string name)
base.Say(rtbox, name + "說英語!");
base其實最大的使用地方在面相對性開發的多态性上,base可以完成建立派生類執行個體時調用其基類構造函數或者調用基類上已被其他方法重寫的方法。
例如:
1關于base調用基類構造函數
public class A
{
public A() { Console.WriteLine("Build A");}
}
public class B:A
public B():base()
Console.WriteLine("Build B");
static void Main()
B b = new B();
Console.ReadLine();
建立一個B的執行個體對象,獲得結果是同時列印Build A和Build B.
2關于base在派生類中調用基類的方法。
public virtual void Hello() { Console.WiriteLine("Hello");}
public class B : A
public override void Hello()
{
base.Hello();//調用基類的方法,顯示Hello
Console.WiriteLine("World");
這樣如果程式調用B.Hello()獲得的效果将會使Hello World.
最後補充下,根據MSDN Library介紹來看這兩個關鍵字都是屬于[通路關鍵字]類型
關于base
base 關鍵字用于從派生類中通路基類的成員:
調用基類上已被其他方法重寫的方法。
指定建立派生類執行個體時應調用的基類構造函數。
基類通路隻能在構造函數、執行個體方法或執行個體屬性通路器中進行。
示例:
1. 在派生類中調用基類方法。
using System;
protected string _className = "BaseClass";
public virtual void PrintName()
Console.WriteLine("Class Name: {0}", _className);
class DerivedClass : BaseClass
public string _className = "DerivedClass";
public override void PrintName()
Console.Write("The BaseClass Name is {0}");
//調用基類方法
base.PrintName();
Console.WriteLine("This DerivedClass is {0}", _className);
class TestApp
public static void Main()
DerivedClass dc = new DerivedClass();
dc.PrintName();
/**/
/*
控制台輸出:
The BaseClass Name is BaseClass
This DerivedClass is DerivedClass
*/
2. 在派生類中調用基類構造函數。
// keywords_base2.cs
int num;
public BaseClass() { Console.WriteLine("in BaseClass()"); }
public BaseClass(int i)
num = i;
Console.WriteLine("in BaseClass(int {0})", num);
public class DerivedClass : BaseClass
// 該構造器調用 BaseClass.BaseClass()
public DerivedClass()
: base()
// 該構造器調用 BaseClass.BaseClass(int i)
public DerivedClass(int i)
: base(i)
static void Main()
DerivedClass dc1 = new DerivedClass(1)();
Console.ReadLine();
/**//*
in BaseClass()
in BaseClass(1)
注意:
從靜态方法中使用 base 關鍵字是錯誤的。
base 主要用于面向對象開發的多态這方面,在示例2中有展現。
關于this
this 關鍵字引用類的目前執行個體。
以下是 this 的常用用途:
限定被相似的名稱隐藏的成員
将對象作為參數傳遞到其他方法
聲明索引器
// this 關鍵字
// keywords_this.cs
class Employee
private string _name;
private int _age;
private string[] _arr = new string[5];
public Employee(string name, int age)
{ // 使用this限定字段,name與age
this._name = name;
this._age = age;
public string Name
get { return this._name; }
public int Age
get { return this._age; }
// 列印雇員資料
public void PrintEmployee()
// 将Employee對象作為參數傳遞到DoPrint方法
Print.DoPrint(this);
// 聲明索引器
public string this[int param]
get { return _arr[param]; }
set { _arr[param] = value; }
class Print
public static void DoPrint(Employee e)
Console.WriteLine("Name: {0}\nAge: {1}", e.Name, e.Age);
Employee E = new Employee("Hunts", 21);
E[0] = "Scott";
E[1] = "Leigh";
E[4] = "Kiwis";
E.PrintEmployee();
for (int i = 0; i < 5; i++)
Console.WriteLine("Friends Name: {0}", E[i]);
控制台輸出:
Name: Hunts
Age: 21
Friends Name: Scott
Friends Name: Leigh
Friends Name:
Friends Name: Kiwis