黑馬程序員-.NET基礎之繼承和多態

------- Windows Phone 7手機開發.Net培訓、期待與您交流! -------

 

封裝、繼承、多態作爲面向對象思想的三大核心思想,作爲初學者,瞭解它們初步的特性,並能寫出簡單的示例代碼,是我們必須要掌握的。可能有人會說,封裝也是面向對象思想的三大核心思想之一啊,你爲什麼不講講,其實,當我在創建一個自定義的類時,就已經在進行封裝了,所以我覺得稍微有點基礎的人,應該都懂。好了,廢話不多說,現將自己整理好的筆記供大家參考。

 

一、繼承和多態的概念

繼承允許重用現有類(基類,亦稱超類、父類)去創建新類(子類,亦稱派生類)的過程。子類將獲取基類的所有非私有數據和行爲,子類可以定義其他數據或行爲派生類具有基類的所有非私有數據和行爲以及新類自己定義的所有其他數據或行爲,即子類具有兩個有效類型:子類的類型和它繼承的基類的類型對象可以表示多個類型的能力稱爲多態性。下面是一個多態性示例。

using System;
namespace CSharpPractice.Polymorphism
{
    public class SimpleClassA
    {
        public SimpleClassA() { }
        public void MethodA()
        {
            Console.WriteLine("調用MethodA()");
        }
    }
    public class SimpleClassB : SimpleClassA
    {
        public SimpleClassB() { }
        public void MethodB()
        {
            Console.WriteLine("調用MethodB()");
        }
    }
    class Test
    {
        static void Main()
        {
            SimpleClassA oSimpleClassA = new SimpleClassA();
            oSimpleClassA.MethodA(); //OK 調用類型SimpleClassA的成員方法
            //SimpleClassB oSimpleClassB1 = (SimpleClassB)oSimpleClassA;//運行錯誤
            SimpleClassB oSimpleClassB = new SimpleClassB();
            oSimpleClassB.MethodB(); //OK 調用類型SimpleClassB的成員方法
            oSimpleClassB.MethodA();// OK 調用基類SimpleClassA的成員方法
            SimpleClassA oSimpleClassA1 = (SimpleClassA)oSimpleClassB;
            oSimpleClassA1.MethodA();
            //oSimpleClassA1.MethodB(); //編譯錯誤 類型SimpleClassA不存在方法MethodB()
            Console.ReadLine();
            SimpleClassB oSimpleClassB1 = (SimpleClassB)oSimpleClassA1;
            oSimpleClassB1.MethodB(); //OK 調用類型SimpleClassB的成員方法
            oSimpleClassB1.MethodA();// OK 調用基類SimpleClassA的成員方法
            Console.ReadKey();
        }
    }
}

 

二、派生類

在聲明派生類時,在類名稱後放置一個冒號,然後在冒號後指定要從中繼承的類(即基類)。派生類可以訪問基類的非private成員,但是派生類的屬性和方法不能直接訪問基類的private成員。派生類可以影響基類private 成員的狀態改變,但只能通過基類提供並由派生類繼承的非private 的屬性和方法來改變,C#不支持多重繼承,即一個派生類只能繼承於一個基類。派生類示例:創建基類Person,包含2個數據成員name和age、1個具有2個參數的構造函數;創建派生類Student,包含1個數據成員studentID、1個具有3個參數的派生類構造函數並用“:base”調用基類構造函數。

using System;
namespace CSharpPractice.DerivedClass
{
    public class Person  //基類 等同於public class Person:Object  
    {
        public string name;
        public uint age;
        public Person(string name, uint age) //基類的構造函數
        {
            this.name = name;
            this.age = age;
        }
    }

    public class Student : Person  //派生類
    {
        public string studentID;
        //派生類構造函數並用“:base”調用基類構造函數
        public Student(string name, uint age, string id)
            : base(name, age)
        {
            this.studentID = id;
        }
    }

    public class TestPersonStudent
    {
        static void Main(string[] args)
        {
            //構造 
            Student objstudent = new Student("Zhangsan", 25, "2008101001");
            Console.WriteLine("name={0},  age={1},  ID={2}", objstudent.name, objstudent.age, objstudent.studentID);
            Console.ReadLine();
        }
    }
}

 

2.訪問關鍵字this和base

this關鍵字引用類的當前實例。靜態成員方法中不能使用this關鍵字。this關鍵字只能在實例構造函數、實例方法或實例訪問器中使用
base關鍵字用於從派生類中訪問基類的成員:
指定創建派生類實例時應調用的基類構造函數
調用基類上已被其他方法重寫的方法
不能從靜態方法中使用 base 關鍵字,base關鍵字只能在實例構造函數、實例方法或實例訪問器中使用。

using System;
namespace CSharpPractice.ThisBase
{
    public class Person  //基類 等同於public class Person:Object  
    {
        public string name;
        public uint age;
        public Person(string name, uint age) //基類的構造函數
        {
            this.name = name; //this關鍵字引用類的當前實例
            this.age = age;  //this關鍵字引用類的當前實例  
        }
        public virtual void GetInfo()
        {
            Console.WriteLine("Name: {0}", name);
            Console.WriteLine("Age: {0}", age);
        }
    }
    public class Student : Person  //派生類
    {
        public string studentID;
        //派生類構造函數並用“:base”調用基類構造函數 
        public Student(string name, uint age, string id)
            : base(name, age)
        {
            this.studentID = id;
        }
        public override void GetInfo()
        {
            //調用基類的方法
            base.GetInfo();
            Console.WriteLine("StudentID: {0}", studentID);
        }
    }
    public class TestPersonStudent
    {
        static void Main(string[] args)
        {
            //構造 
            Student objstudent = new Student("Zhangsan", 25, "2008101001");
            objstudent.GetInfo();
            Console.ReadLine();
        }
    }
}

3.虛方法、重寫方法和隱藏方法

在基類中使用關鍵字virtual定義虛方法(virtual method);然後派生類中使用關鍵字override來重寫方法(override method),或使用關鍵字new來覆蓋方法(隱藏方法)。重寫方法用相同的簽名重寫所繼承的虛方法。虛方法聲明用於引入新方法,而重寫方法或隱藏方法聲明則用於使現有的繼承虛方法專用化(通過提供該方法的新實現)。調用虛方法時,將首先檢查該對象的運行時類型,並調用派生類中的該重寫成員,如果沒有派生類重寫該成員,則調用其原始成員。默認情況下,C#方法是非虛擬的。不能重寫非虛方法。除了類方法,還可以使用virtual關鍵字修飾的其他類成員以定義虛成員,包括:屬性、索引器或事件聲明。虛擬成員的實現可在派生類中使用關鍵字override來重寫;或使用關鍵字new來覆蓋。

using System;
namespace CSharpPractice.Virtual
{
    class TestClass
    {
        public class Dimensions  //基類
        {
            public const double PI = Math.PI;
            protected double x, y;
            public Dimensions()
            {
            }
            public Dimensions(double x, double y)
            {
                this.x = x;
                this.y = y;
            }
            public virtual double Area()
            {
                return x * y;
            }
        }
        public class Circle : Dimensions //派生類:圓
        {
            public Circle(double r)
                : base(r, 0)
            {
            }
            public override double Area()
            {  //圓的面積
                return PI * x * x;
            }
        }
        class Sphere : Dimensions  //派生類:球體
        {
            public Sphere(double r)
                : base(r, 0)
            {
            }
            public override double Area()
            {  // 球體表面積
                return 4 * PI * x * x;
            }
        }
        class Cylinder : Dimensions  //派生類:圓柱體
        {
            public Cylinder(double r, double h)
                : base(r, h)
            {
            }
            public override double Area()
            {  //圓柱體表面積
                return 2 * PI * x * x + 2 * PI * x * y;
            }
        }
        static void Main()
        {
            double r = 3.0, h = 5.0;
            Dimensions c = new Circle(r);      //圓
            Dimensions s = new Sphere(r);      //球體
            Dimensions l = new Cylinder(r, h); //圓柱體
            // 顯示各種不同形狀的(表)面積:
            Console.WriteLine("Area of Circle   = {0:F2}", c.Area());
            Console.WriteLine("Area of Sphere   = {0:F2}", s.Area());
            Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
            Console.ReadKey();
        }
    }
}

 

三、抽象類和抽象方法


將關鍵字 abstract 置於關鍵字 class 的前面可以將類聲明爲抽象類。抽象類不能實例化,抽象類一般用於提供多個派生類可共享的基類的公共定義。例如,類庫可以定義一個包含基本功能的抽象類,並要求程序員使用該庫通過創建派生類來提供自己的類實現。抽象類與非抽象類相比,具有下列特徵:
1.抽象類不能直接實例化,對抽象類使用new運算符會導致編譯時錯誤。可以定義抽象類型的變量,但其值必須爲 null,或者是其派生的非抽象類的實例的引用
2.允許(但不要求)抽象類包含抽象成員
3.抽象類不能被密封
4.當從抽象類派生非抽象類時,這些非抽象類必須實現所繼承的所有抽象成員,從而重寫那些抽象成員

using System;
namespace CSharpPractice.Abstract
{
    abstract class Animal   // 基類Animal:抽象類
    {
        public abstract void SayHello();
    }
    class Dog : Animal     // 派生類Dog
    {
        public override void SayHello()
        {   //重寫SayHello()
            Console.WriteLine("Wow Wow!");
        }
    }
    class Cat : Animal     // 派生類Cat
    {
        public override void SayHello()
        {   //重寫SayHello()
            Console.WriteLine("Mew Mew!");
        }
    }
    class TestClass
    {
        static void Main()
        {
            Animal[] animals =
        {
            new Dog(),
            new Cat()
        };
            foreach (Animal a in animals)
            {
                a.SayHello();
            }
            Console.ReadKey();
        }
    }
}

 

四、接口

一個接口定義一個協定。接口本身不提供它所定義的成員的實現,接口只指定實現該接口的類或結構必須提供的成員,繼承接口的任何非抽象類型都必須實現接口的所有成員。接口類似於抽象基類,接口不能實例化。接口中聲明的所有成員隱式地爲public和abstract。接口可以包含事件、索引器、方法和屬性,但接口不能包含字段。下面給出兩個接口實現示例。

using System;
namespace CSharpPractice.Interface
{
    public interface IBankAccount  // 銀行賬戶
    {
        void PayIn(decimal amount);      // 存款
        bool Withdraw(decimal amount);   // 取款,並返回是否成功
        decimal Balance                // 餘額
        {
            get;
        }
    }
    public interface ITransferBankAccount : IBankAccount  // 轉賬銀行賬戶
    {
        bool TransferTo(IBankAccount destination, decimal amount);
    }
    public class CurrentAccount : ITransferBankAccount   // 當前賬戶
    {
        private decimal balance;
        public void PayIn(decimal amount)
        {    // 存款
            balance += amount;
        }
        public bool Withdraw(decimal amount)
        {   // 賬戶有足夠餘額,則取款,並返回是否成功
            if (balance >= amount)
            {
                balance -= amount;
                return true;
            }
            Console.WriteLine("餘額不足,取款失敗!");
            return false;
        }
        public decimal Balance
        {   // 返回餘額
            get
            {
                return balance;
            }
        }
        public bool TransferTo(IBankAccount destination, decimal amount)
        {   // 銀行轉賬
            bool result;
            if ((result = Withdraw(amount)) == true)
                destination.PayIn(amount);
            return result;
        }
        public override string ToString()
        {   // 返回銀行當前賬戶中的餘額
            return String.Format("Jupiter Bank Current Account: Balance = {0,6:C}", balance);
        }
    }
    class TestClass
    {
        static void Main()
        {   // 當前賬戶
            IBankAccount venusAccount = new CurrentAccount();
            // 轉賬賬戶
            ITransferBankAccount jupiterAccount = new CurrentAccount();
            // 當前賬戶存款
            venusAccount.PayIn(200);
            // 轉賬到轉賬賬戶
            jupiterAccount.PayIn(500);
            // 轉賬賬戶再轉賬到當前賬戶
            jupiterAccount.TransferTo(venusAccount, 100);
            // 顯示賬戶餘額
            Console.WriteLine(venusAccount.ToString());
            Console.WriteLine(jupiterAccount.ToString());
            Console.ReadLine();
        }
    }
}

好了,關於繼承和多態的筆記就寫到這裏吧。
 

------- Windows Phone 7手機開發.Net培訓、期待與您交流! -------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章