在前一篇文章中,我們講了面向對象的特征之一(封裝),那麼今天我們來了解面向對象的剩余兩大特性。
一、繼承 1、定義 繼承就是從父類中獲取一些公開的成員,如方法和屬性。C#中只允許繼承一個父類,但允許繼承多個接口。如果子類繼承接口,則必須實現接口中定義的所有公開成員。 公開成員是指在父類中定義為public的成員(public的作用域可在子類中生效,而private作用域則不可) 子類繼承父類: 子類擁有父類非Private的屬性和功能; 子類具有自己的屬性和功能,即子類可以擴展父類沒有的屬性和功能; 子類還可以以自己的方式實現父類的功能(方法重寫)2、繼承的兩大特性:
001. 單根性:一個子類不能同時繼承多個父類。
002. 傳遞性:如果有一個類A繼承與類B,又有一個類C繼承與類A,那麼類C也可以使用類B中非私有的字段,屬性和方法。
3.子類構造執行流程?
解析: 第一步:先進入子類構造參數列表
第二步:進入父類對應的構造
第三步:執行父類構造的方法體
第四步:回到子類方法體執行.
4、優點 繼承使得所有子類公共部分都放在父類中,使得代碼得到共享,這就避免了重復。此外,繼承可使得修改或擴展繼承而來的實現都較為容易。 5、注意 Protected表示繼承時子類可以對基類有完全訪問權。也就是說protected修飾的類成員,對子類公開,段不對其他類公開。 實例:1 private void button1_Click(object sender,EventArgs e) 2 3 { 4 5 Cat cat = new Cat("咪咪");//將類實例化 Cat cat聲明一個Cat對象,對象名為cat;newCat()將此cat對象實例化 6 7 cat.ShoutNum = 5; //給屬性賦值 8 9 MessageBox.Show(cat.Shout()); 10 11 } 12 13 class Animal //定義父類 14 15 { 16 17 protected string name =""; //注意變為Protected 子類可以繼承 18 19 public Animal(string name) 20 21 { 22 23 this.name = name; 24 25 26 27 } 28 29 public Animal() 30 31 { 32 33 this.name = "無名"; 34 35 } 36 37 protected int shoutNum = 3; //變為protected 38 39 public int ShoutNum 40 41 { 42 43 get 44 45 { 46 47 return shoutNum; 48 49 } 50 51 set 52 53 { 54 55 shoutNum = value; 56 57 } 58 59 } 60 61 } 62 63 class Cat : Animal //注意變化 64 65 { 66 67 public Cat() : base() //子類構造方法需要調用父類同樣參數類型的構造方法,用base關鍵字代表父類 68 69 { } 70 71 public Cat(string name):base(name) //注意變化 72 73 { } 74 75 public string Shout() 76 77 { 78 79 string result = ""; 80 81 for (int i = 0; i <shoutNum; i++) 82 83 result += "喵!"; 84 85 return "我的名字叫:" +name + "" + result; 86 87 } 88 89 } 90 91 class Dog : Animal //注意變化 92 93 { 94 95 public Dog() : base() 96 97 { } 98 99 public Dog(string name): base(name) 100 101 { } 102 103 public string shout() 104 105 { 106 107 string result = ""; 108 109 for (int i = 0; i <shoutNum; i++) 110 111 result += "汪!"; 112 113 return "我的名字叫:" +name + "" + result; 114 115 } 116 117 } 118 119 private void button2_Click(objectsender, EventArgs e) 120 121 { 122 123 Dog dog = new Dog("狗");//將類實例化 Cat cat聲明一個Cat對象,對象名為cat;newCat()將此cat對象實例化 124 125 dog.ShoutNum = 5; //給屬性賦值 126 127 MessageBox.Show(dog.shout()); 128 129 }
二、多態
1、定義 多態是指類可以有多種形態,通過修改可以形成多個實現方法。子類從父類繼承時它會獲得父類的所有方法、字段、屬性、事件。多態表示不同的對象可以執行相同的操作,但要通過它們自己的實現代碼來執行。通俗的說:不同的對象對於同一個指令做出的響應不同,就是多態。 若要改變父類的數據和行為,兩種方式:可創建新的成員替換父級成員,或者可以重寫虛擬的父級成員。 (1)若要替換父級成員,需要使用new關鍵字。下面是GetName方法的兩種形態,一種是返回父級名稱,一種是返回子級名稱。1 第一種:返回父級名稱 2 3 class PerentClass //父類 4 5 { 6 7 public string GetName() 8 9 { 10 11 return"父級名稱"; 12 13 } 14 15 } 16 17 第二種:返回子級名稱 18 19 class SonClass:PerentClass //子類繼承父類 20 21 { 22 23 public new string GetName() 24 25 { 26 27 return"子級名稱"; 28 29 } 30 31 } 32
(2)重寫虛擬的父級成員的兩個條件:父級成員使用關鍵字“virtual”;子級成員使用“override”。
1 class PerentClass //父類 2 3 { 4 5 public virtual string GetName() 6 7 { 8 9 return"父級名稱"; 10 11 } 12 13 } 14 15 16 17 class SonClass:PerentClass //子類繼承父類 18 19 { 20 21 public override string GetName() 22 23 { 24 25 return"子級名稱"; 26 27 } 28 29 }
(2):抽象方法實現多態
1 /// <summary> 2 /// 鳥類:基類 3 /// </summary> 4 public abstract class Bird 5 { 6 /// <summary> 7 /// 吃:抽象方法 8 /// </summary> 9 public abstract void Eat(); 10 }
1 /// <summary> 2 /// 喜鵲:子類 3 /// </summary> 4 public class Magpie:Bird 5 { 6 /// <summary> 7 /// 重寫父類中Eat方法 8 /// </summary> 9 public override void Eat() 10 { 11 Console.WriteLine("我是一只喜鵲,我喜歡吃蟲子~"); 12 } 13 }
1 /// <summary> 2 /// 老鷹:子類 3 /// </summary> 4 public class Eagle:Bird 5 { 6 /// <summary> 7 /// 重寫父類中Eat方法 8 /// </summary> 9 public override void Eat() 10 { 11 Console.WriteLine("我是一只老鷹,我喜歡吃肉~"); 12 } 13 }
1 /// <summary> 2 /// 企鵝:子類 3 /// </summary> 4 public class Penguin:Bird 5 { 6 /// <summary> 7 /// 重寫父類中Eat方法 8 /// </summary> 9 public override void Eat() 10 { 11 Console.WriteLine("我是一只小企鵝,我喜歡吃魚~"); 12 } 13 }
1 static void Main(string[] args) 2 { 3 //創建一個Bird基類數組,添加 Magpie對象,Eagle對象,Penguin對象 4 Bird[] birds = { 5 new Magpie(), 6 new Eagle(), 7 new Penguin() 8 }; 9 //遍歷一下birds數組 10 foreach (Bird bird in birds) 11 { 12 bird.Eat(); 13 } 14 Console.ReadKey(); 15 }
執行結果:
2,抽象類可以被繼承嗎?
可以,不僅可以被普通類繼承,也可以被抽象類繼承
3,抽象方法可以有方法體嗎?
不可以,連花括號都不能有
4,簡述抽象方法和虛方法的區別?
1 //01.定義一個抽象類,用abstract 修飾 2 3 //02.抽象方法不能有方法體,甚至連{}都不能有 4 5 //03.抽象方法只能存在於抽象類中,但是抽象類中可以有非抽象方法 6 7 //04.抽象類不能實例化 8 9 //05.抽象類中抽象方法只是用來規定方法的形式(參數,返回值),約束子類方法的形式 10 11 //06.抽象類中的抽象成員必須在子類中全部實現,除非子類也是抽象類 12 13 //07.子類實現抽象方法的快捷鍵,Ctrl+.(沒有輸入法情況下 ) 14 15 //shift+alt+F10 16 17 //08.抽象類不能用static修飾:如果是static,抽象就無法被繼承,也就失去了抽象類本身的意義
5、注意 子類以父類省份出現 子類在工作中以自己的方式來實現 子類乙父類的身份出現時,子類特有的屬性和方法不可同時使用 使用多態時,需了解:虛方法和方法重寫 為了使子類的實例完全接替來自父類的成員,父類必須將該成員聲明為虛擬的。這是通過在該成員的返回類型之前添加virtual來實現。 子類選擇使用override關鍵字,將父類實現替換為自己的實現,這就是方法重寫。 說了這麼多,那麼我們用一個具體案例實現一下吧! 程序效果圖如下: 關鍵代碼如下:
//父類 public abstract class Vehicle//抽象類 { public string Color { get; set; }//顏色 public double DailyRent { get; set; }//租金 public string LiceseNo { get; set; }//車牌號 public string Name { get; set; }//車名 public int RentDate { get; set; }//租用天數 public string RentUser { get; set; }//租用者 public int YearsOfService { get; set; }//使用時間 public Vehicle() { } public Vehicle(string color,double dailyRent,string liceseNo,string name,int yearOfSerivce) //父類中的帶參數構造 { this.Color = color; this.DailyRent = dailyRent; this.LiceseNo = liceseNo; this.Name = name; this.YearsOfService = yearOfSerivce; } public abstract double CalPrice();//父類中計算租車金額的抽象方法 }
1 //子類繼承父類Vehicle 2 class Car:Vehicle 3 { 4 public Car(){} 5 public Car(string color, double dailyRent, string liceseNo, string name,int yearOfSerivce) 6 : base(color,dailyRent,liceseNo,name,yearOfSerivce) //給父類中的各個屬性復制 7 { 8 9 } 10 public override double CalPrice()//重寫父類中租車的抽象方法 11 { 12 double price = base.RentDate * base.DailyRent; 13 return price; 14 } 15 }
1 //子類Trcuk繼承父類Vehicle 2 public class Truck:Vehicle 3 { 4 private int load;//卡車的載重量 5 6 public int Load//封裝字段 7 { 8 get { return load; } 9 set { load = value; } 10 } 11 public Truck(int load, string color, double dailyRent, string liceseNo, string name, int yearOfSerivce) 12 : base(color, dailyRent, liceseNo, name, yearOfSerivce) 13 { 14 this.Load = load; 15 } 16 public Truck() { } 17 public override double CalPrice()//卡車類重寫父類中計算租車金額的抽象方法 18 { 19 double price = base.RentDate * base.DailyRent; 20 return price; 21 } 22 }
1 public partial class Form1 : Form 2 { 3 public Form1() 4 { 5 InitializeComponent(); 6 } 7 //保存可租用車集合信息 8 Dictionary<string, Vehicle> vehicles = new Dictionary<string, Vehicle>(); 9 //保存租出車輛信息 10 Dictionary<string, Vehicle> rentVehicles = new Dictionary<string, Vehicle>(); 11 /// <summary> 12 /// 初始化幾個可租用車信息 13 /// </summary> 14 private void Initail() 15 { 16 Car car = new Car(); 17 car.LiceseNo = "京RO123456"; 18 car.Name = "奧迪A6"; 19 car.Color= "黑色"; 20 car.YearsOfService = 3; 21 car.DailyRent = 250; 22 Car car1 = new Car(); 23 car1.LiceseNo = "京B32197"; 24 car1.Name = "大眾2000"; 25 car1.Color = "藍色"; 26 car1.YearsOfService = 3; 27 car1.DailyRent = 450; 28 Truck truck = new Truck(); 29 truck.LiceseNo = "豫S46541"; 30 truck.Name = "東風"; 31 truck.Color = "藍色"; 32 truck.YearsOfService = 2; 33 truck.DailyRent = 500; 34 truck.Load = 20; 35 vehicles.Add(car.LiceseNo,car); 36 vehicles.Add(car1.LiceseNo,car1); 37 vehicles.Add(truck.LiceseNo,truck); 38 } 39 private void Form1_Load(object sender, EventArgs e) 40 { 41 Initail(); 42 43 this.txtLoad.Enabled = false; 44 } 45 /// <summary> 46 /// 更新可租車輛數據 47 /// </summary> 48 private void UpdatelvRent() 49 { 50 this.lvRent.Items.Clear(); 51 52 foreach (Vehicle item in vehicles.Values)//循環遍歷集合中的數據,添加到ListView空間中 53 { 54 ListViewItem lvitem = new ListViewItem(item.LiceseNo); 55 if (item is Car)//判斷item是否是Car類形 56 { 57 lvitem.SubItems.Add(item.Name); 58 lvitem.SubItems.Add(item.Color); 59 lvitem.SubItems.Add(item.YearsOfService.ToString()); 60 lvitem.SubItems.Add(item.DailyRent.ToString()); 61 62 } 63 if (item is Truck) 64 { 65 lvitem.SubItems.Add(item.Name); 66 lvitem.SubItems.Add(item.Color); 67 lvitem.SubItems.Add(item.YearsOfService.ToString()); 68 lvitem.SubItems.Add(item.DailyRent.ToString()); 69 lvitem.SubItems.Add(((Truck)item).Load.ToString()); 70 } 71 72 this.lvRent.Items.Add(lvitem); 73 } 74 } 75 private void btnQueryRent_Click(object sender, EventArgs e)//點擊刷新按鈕事件,調用刷新租車信息方法 76 { 77 UpdatelvRent(); 78 } 79 80 private void btnRent_Click(object sender, EventArgs e)//點擊租車按鈕事件 81 { 82 if (this.lvRent.SelectedItems.Count > 0 )//判斷是否是選中的租車信息 83 { 84 if ( this.txtRenter.Text == string.Empty)//租車者不能為空 85 { 86 MessageBox.Show("租用者不能為空!!"); 87 return; 88 } 89 foreach (Vehicle item in vehicles.Values) 90 { 91 if (item is Car)//判斷item是否是Car類形 92 { 93 if (this.lvRent.SelectedItems[0].SubItems[0].Text == item.LiceseNo) 94 { 95 vehicles[this.lvRent.SelectedItems[0].SubItems[0].Text].RentUser = this.txtRenter.Text; 96 rentVehicles.Add(item.LiceseNo, item);//添加到租車車輛信息的集合中 97 vehicles.Remove(item.LiceseNo);//從可租車輛信息的集合中刪除選中的車輛信息 98 MessageBox.Show("租車成功!!!"); 99 this.txtRenter.Text = ""; 100 break; 101 } 102 } 103 if (item is Truck)//同理之上 104 { 105 if (this.lvRent.SelectedItems[0].SubItems[0].Text == ((Truck)item).LiceseNo) 106 { 107 vehicles[this.lvRent.SelectedItems[0].SubItems[0].Text].RentUser = this.txtRenter.Text; 108 109 vehicles.Remove(((Truck)item).LiceseNo); 110 rentVehicles.Add(((Truck)item).LiceseNo, item); 111 MessageBox.Show("租車成功!!!"); 112 this.txtRenter.Text = ""; 113 break; 114 } 115 } 116 117 } 118 UpdatelvRent();//刷新數據 119 } 120 else 121 { 122 MessageBox.Show("請選擇一輛車租"); 123 } 124 125 126 } 127 128 private void btnExit_Click(object sender, EventArgs e)//點擊退出按鈕事件 129 { 130 this.Close(); 131 } 132 /// <summary> 133 /// 更新還車信息 134 /// </summary> 135 private void UpdateLvRentu() 136 { 137 this.lvReturn.Items.Clear(); 138 foreach (Vehicle item in rentVehicles.Values) 139 { 140 ListViewItem lvitem = new ListViewItem(item.LiceseNo); 141 if (item is Car) 142 { 143 lvitem.SubItems.Add(item.Name); 144 lvitem.SubItems.Add(item.Color); 145 lvitem.SubItems.Add(item.YearsOfService.ToString()); 146 lvitem.SubItems.Add(item.DailyRent.ToString()); 147 148 } 149 if (item is Truck) 150 { 151 lvitem.SubItems.Add(item.Name); 152 lvitem.SubItems.Add(item.Color); 153 lvitem.SubItems.Add(item.YearsOfService.ToString()); 154 lvitem.SubItems.Add(item.DailyRent.ToString()); 155 lvitem.SubItems.Add(((Truck)item).Load.ToString()); 156 } 157 158 this.lvReturn.Items.Add(lvitem); 159 } 160 } 161 private void btnQueryReturn_Click(object sender, EventArgs e) 162 { 163 164 UpdateLvRentu(); 165 } 166 167 private void btnCompute_Click(object sender, EventArgs e) 168 { 169 if (this.lvReturn.SelectedItems.Count > 0)//必須有選中的車輛 170 { 171 if (this.txtRentDate.Text==string.Empty)//租車天數不能為空 172 { 173 MessageBox.Show("請輸入租車天數!!"); 174 return; 175 } 176 rentVehicles[this.lvReturn.SelectedItems[0].SubItems[0].Text].RentDate = Convert.ToInt32(this.txtRentDate.Text); 177 double price = rentVehicles[this.lvReturn.SelectedItems[0].SubItems[0].Text].CalPrice(); 178 MessageBox.Show("您的總價是" + price.ToString(), "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);//顯示租車金額 179 if (rentVehicles.ContainsKey(this.lvReturn.SelectedItems[0].SubItems[0].Text))//判斷租出車輛信息集合中是否存在還車的車輛 180 { 181 182 vehicles.Add(rentVehicles[this.lvReturn.SelectedItems[0].SubItems[0].Text].LiceseNo, rentVehicles[this.lvReturn.SelectedItems[0].SubItems[0].Text]);//再度添到可租車輛集合中 183 rentVehicles.Remove(this.lvReturn.SelectedItems[0].SubItems[0].Text);//從租出車輛集合中移除 184 } 185 UpdateLvRentu();//刷新信息 186 } 187 else 188 { 189 MessageBox.Show("請選擇一輛車進行歸還!!"); 190 } 191 192 } 193 194 private void btnAdd_Click(object sender, EventArgs e) 195 { 196 197 if (this.rdoCar.Checked)//判斷哪個按鈕選中,添入不同的車輛信息 198 { 199 200 Car car = new Car(this.cobColor.Text, Convert.ToInt32(this.txtLetting.Text), this.txtAutoNum.Text, this.txtName.Text,Convert.ToInt32(this.txtYears.Text)); 201 vehicles.Add(this.txtName.Text, car); 202 MessageBox.Show("入庫成功!!"); 203 } 204 else 205 { 206 this.txtLoad.Enabled = true; 207 Truck car = new Truck(Convert.ToInt32(this.txtLoad.Text), this.cobColor.Text, Convert.ToInt32(this.txtLetting.Text), this.txtAutoNum.Text, this.txtName.Text, Convert.ToInt32(this.txtYears.Text)); 208 vehicles.Add(this.txtName.Text, car); 209 MessageBox.Show("入庫成功!!"); 210 } 211 212 } 213 214 private void rdoTruck_CheckedChanged(object sender, EventArgs e)//單選鈕點擊改變事件,將載重文本框設為可用 215 { 216 if (this.rdoTruck.Checked) 217 { 218 this.txtLoad.Enabled = true; 219 220 } 221 else 222 { 223 this.txtLoad.Enabled = false; 224 } 225 } 226 }