筆記7 面向對象的三大特性、值類型和引用類型、抽象類、接口、委託
特性1:封裝
將類裏面的成員變量和方法進行私有化,如果外界要訪問,向外界提供統一的訪問方法。
基於;訪問修飾符。
優點:減少耦合,防止外界進行修改。
實現方式:
1、編寫public方法進行私有變量或方法的封裝。
2、屬性。
對成員變量的封裝
public class Person
{
private int age; //privare私有的。
//變量首選都設爲私有的,如果外界要訪問,就開一個方法。
public void SetAge(int value) //外界可以傳入參數value
{
if (value > 0 && value < 100)
{
age = value;
}
}
public int GetAge()
{
return age;
}
}
對方法的封裝
public class Person
{
private int age; //privare私有的。
//變量首選都設爲私有的,如果外界要訪問,就開一個方法。
//暴露給外界
public void NewFunc() //寫一個方法,不寫參數
{
Eat(age);
}
//內部
private void Eat(int age)
{
Console.WriteLine("我的年齡是" + age);
//加號可以將age轉換成字符串類型,然後與前面相加。
}
特性2:繼承
創建新的類(派生類、子類),可以繼承現有類(基類、父類)的特性,並且還可以進行修改和擴充。
C#是單繼承,C++是多繼承。
單繼承:一個父類可以有多個子類,但父類只有一個。
多繼承:一個父類可以有多個子類,且父類可以有多個。
繼承現有類(基類、父類)的特性
修改現有類特性(子類想更改)
覆蓋(覆寫):未經父類允許(new)
覆蓋(覆寫):把原本的方法(父類的)覆蓋了
父類
public class LaoWang //這個類叫LaoWang
{
public void Play()
{
Console.WriteLine("我要去喝酒");
}
子類
public class XiaoWang : LaoWang
{
public XiaoWang()
{
}
//覆蓋(覆寫):把原本的方法(父類的)覆蓋了
//確定不用父類的某個方法,要用自己的,那麼就new
public new void Play()
{
Console.WriteLine("我要玩遊戲");
}
}
重寫:獲得父類允許(父類:虛方法virtual、子類override)
重寫:利用virtual和override這一對
父類(虛方法virtual:可以被重寫)
public class LaoWang //這個類叫LaoWang
{
//虛方法:可以被重寫
public virtual void Eat() //virtual表示其子類此方法可以重寫
{
Console.WriteLine("我喜歡喫青椒");
}
}
子類(override)
//寫一個子類,即便子類裏什麼也沒寫,它也具有父類的特性。
//格式:子類名字:父類名字
public class XiaoWang : LaoWang
{
public XiaoWang()
{
}
//重寫:利用virtual和override這一對
public override void Eat() //override表示告訴父類,我重寫了這個方法
{
Console.WriteLine("我喜歡喫肉");
}
外圍
class Program
{
static void Main(string[] args)
{
XiaoWang xw = new XiaoWang(); //實例化一個xw
xw.Play();
xw.Eat();
Console.ReadKey();
}
}
擴充現有類特性
普通方法(需要在重寫的基礎上進行,利用關鍵詞base)
關鍵詞this表示當前類所產生的對象,關鍵詞base代表我的父類。
在寫我的特性前,利用base調用父類的特性。
子類
//重寫:利用virtual和override這一對
public override void Eat() //override表示告訴父類,我重寫了這個方法
{
//關鍵詞this表示當前類所產生的對象
//關鍵詞base代表我的父類
base.Eat(); //在寫我的特性前,調用父類的特性
Console.WriteLine("我喜歡喫肉");
/*外界調用結果:我喜歡喫青椒
我喜歡喫肉
*/
}
構造方法
調用構造方法時,默認先調用父類的構造方法,之後調用子類的構造方法。
構造方法無參數(不需要利用關鍵詞base)
父類
//構造方法
public LaoWang()
{
Console.WriteLine("我是老王");
}
子類
public XiaoWang() //構造方法
{
Console.WriteLine("我是小王");
}
外界
XiaoWang xw = new XiaoWang(); //new,調用XiaoWang的方法
/*結果:我是老王
我是小王
*/
構造方法帶參數(有無base)
1、無base:無論子類的構造方法寫成什麼樣,都會調用父類默認的構造方法(不帶參數)。
2、有base,且base有參數:通過base,可以指定調用父類的有相同類型參數的構造方法。
3、有base,但base無參數:調用的便是沒有參數的構造方法。結果和無base一樣。
XiaoWang xw = new XiaoWang(); //new,調用XiaoWang的方法
//構造方法可以帶參數
//“:base(age)”表示先調父類的這個有int類型參數構造方法。把20傳給父輩
public XiaoWang(int age):base(age)
{
Console.WriteLine("我是小王,今年" + age);
}
方法的重載(區別於重寫)
方法的重載:寫了一個同名、但不同參數的的方法。
這兩個方法是可以同時存在的。區別在於外界調用的時候,依據參數的個數或者類型,確定調用何種方法。
重寫與重載的區別
重寫,涉及父類與子類的關係。
重載,是當前類裏的關係。
特性3:多態
C#:父類類型可以接收子類對象,以至於調用同樣方法產生不同的結果。
C++:同樣的指針可以指向不同的子類對象。
接口也是實現多態的一種方式。
實例化時,可用父類類型接收
//實例化一個xb
XiaoBai xb = new XiaoBai();
//NPC xb = new XiaoBai();
NPC npc1 = xb;
多態的作用
如同概念,創建一個父類類型的數組,接收子類對象,以至於調用同樣方法產生不同的結果。
此處由於xb和cs都是文字,所以“不同結果”沒展示出來。
//new一個NPC數組。數組裏包含xb和cs。xb和cs是模具內實例化出的兩個變量。
NPC[] npcs = new NPC[] { xb, cs };
/*此處,我們不需要知道xb和cs的具體類型的。
只要知道二者都是一個父類,父類裏面是Say方法,
通過遍歷,就可以得到二者內容。*/
//快速遍歷
foreach (NPC npc in npcs)
{
npc.Say();
//原本調方法是:“名稱()”。此處是“實例名稱.模具裏該方法的名稱()”。
}
值類型和引用類型的區別
值類型:其餘類型
引用類型:數組、類(別忘了string(數組))、接口、委託
邏輯上將內存分爲兩部分:棧(一個個格子)、堆(剩餘大片區域)。
抽象類(abstract,對應override)
提供了部分功能的實現,不能被實例化的類(不能把它new出來)。除了不能實例化和可能包含抽象方法兩個特點,其餘使用和正常類一樣。
父類
//抽象類(不能被實例化) 添加關鍵字abstract
public abstract class NPC
{
/*可以包含抽象方法:子類必須實現的方法。
抽象方法只能包含在抽象類當中。添加關鍵字abstract。*/
public abstract void Say();
/*抽象方法是子類必須實現的方法,在本類當中是不允許實現的。
所以,把原本的{}去掉,直接分號結束。
{}是方法體,有{}即代表方法實現。*/
}
子類
public class XiaoBai : NPC //創建XiaoBai,XiaoBai繼承NPC
{
//此處,XiaoBai必須把父類不可以實現的方法實現。
//添加關鍵字override
public override void Say()
{
}
}
外界
/*NPC npc1 = new NPC();
因爲此處NPC是個抽象類,不能new,只能new XiaoBai()。*/
//一new XiaoBai(),可以用NPC接收。這是因爲多態性依舊保留。
NPC npc = new XiaoBai();
接口
接口寫法(interface)
同樣不能被實例化,包含的方法必須在繼承該接口的類上實現。一個類可以繼承多個接口。(c#是單繼承(只有一個父類),所以它通過接口實現了多繼承的問題)
//創建XiaoBai,XiaoBai繼承NPC。
//XiaoBai除了是NPC,還是Enemy。在父類後面添加逗號接口名稱。
public class XiaoBai : NPC, Enemy
{
//此處,XiaoBai必須把父類不可以實現的方法實現。
//添加關鍵字override
public override void Say()
{
}
//必須實現接口裏的方法
/*通過接口,強制讓XiaoBai實現GetHit(受到攻擊)的方法。
XiaoBai就變成了敵人,我們就可以攻擊它了。*/
public void GetHit()
{
}
}
//接口 interface
public interface Enemy
{
//接口裏面不能寫變量,只能寫方法。而且方法默認爲public,所以不用寫public。
void GetHit(); //敵人有個方法是受到攻擊。
//誰實現了Enemy這個接口,誰就有了Enemy的特性:受到攻擊。
}
接口可以繼承
//創建XiaoBai,XiaoBai繼承NPC。
//XiaoBai除了是NPC,還是Enemy。在父類後面添加逗號接口名稱。
public class XiaoBai : NPC, Boss
{
//XiaoBai必須把父類不可以實現的方法實現。添加override
public override void Say()
{
}
/*必須實現接口裏的方法。
注意因爲Boss繼承了Enemy受傷害的方法,自身又有扔技能的方法,所以它其實是有兩個方法!
所以在實現時,注意要實現兩個方法!*/
public void GetHit()
{
}
//必須在實現Boss特有的技能
public void Skill()
{
}
}
//接口 interface
public interface Enemy
{
void GetHit(); //敵人有個方法是受到攻擊。
}
//接口是可以繼承的
public interface Boss : Enemy //Boss繼承於Enemy
{
void Skill(); //Boss會扔技能
}
接口也可以實現多態性
委託
第一種寫法(需要new)
public class Person
{
/*創建一個委託類型(關鍵字delegate)。
要求:存放一個返回值爲void,有一個參數爲int類型的方法,類型爲Func。
public delegate void Func(int bbb);
//通過剛纔創建的委託,聲明一個委託
public Func func;
public Person() //構造方法
{
//委託需要new。在()裏寫上要保存的方法名稱。
//func = new Func(Say); 第一種寫法
func(2); //作用就是可以直接將委託當方法去用
}
public void Say(int a)
{
Console.WriteLine("我叫小白");
}
}
第二種寫法(利用+=和-=)
public Person() //構造方法
{
//第二種寫法:
func += Say;
func(2);
}
這種寫法的好處:
委託可以保存多個方法。如果它保存了多個方法,那麼在執行時,它保存的方法會被依次調用。