[Object-oriented] 繼承

[Object-oriented] : 繼承


前言 :

繼承
是物件導向初學者,學完之後。覺得懂卻又有點模糊的東西
筆者試著用展開程式碼的方式,來解釋繼承的運作。


繼承 :

底下是一段繼承的程式碼
這個程式碼很簡單,就是ClassB繼承ClassA而已

namespace ConsoleApplication1 
{ 
    public class ClassA
    {
        public void XXX()
        {
            // ClassA Code
        }

        private void YYY()
        {
            // ClassA Code
        }

        protected void ZZZ()
        {
            // ClassA Code
        }
    }

    public class ClassB : ClassA
    {
        public void AAA()
        {
            // ClassB Code
        }
    }	
}

我們在理解上,可以將這段程式碼展開成這樣

namespace ConsoleApplication1 
{ 
    public class ClassA
    {
        public void XXX()
        {
            // ClassA Code
        }

        private void YYY()
        {
            // ClassA Code
        }

        protected void ZZZ()
        {
            // ClassA Code
        }
    }

    public class ClassB : ClassA
    {
        private ClassA base = new ClassA();

        public void XXX()
        {
            base.XXX();
        }

        protected void ZZZ()
        {
            base.ZZZ();
        }

        public void AAA()
        {
            // ClassB Code
        }
    }
}

當我們使用了繼承的語法,ClassB繼承ClassA的時候
我們可以看成編譯器的動作為:
1. 保留ClassB內的所有成員。
2. 在ClassB內建立一個名為base的ClassA物件。
3. 把ClassA內所有不是標示為private的所有成員,展開成為ClassB的成員。
4. 在ClassB展開的成員內,全部設訂為呼叫ClassA的成員。

這樣的思路看下來,
應該就可以理解繼承,是如何的運作。


存取修飾詞 :

這邊再來說明繼承會使用到的存取修飾詞:public、protected、private


當ClassA內的成員:
宣告為public,   展開程式碼的時候:展開成為ClassB的 public成員。
宣告為protected,展開程式碼的時候:展開成為ClassB的 protected成員。
宣告為private,  展開程式碼的時候:不作任何的動作。


當我們針對類別成員使用不同的存取修飾詞,對於延生的類別而言,會產生不同的影響。


覆寫 :

最後再來說一個覆寫好了
當我們寫了這樣一段程式碼

namespace ConsoleApplication1 
{ 
    public class ClassC
    {
        public virtual void XXX()
        {
            // ClassC Code
        }

        public virtual void YYY()
        {
            // ClassC Code
        }
    }

    public class ClassD : ClassC
    {
        public override void XXX()
        {
            // ClassD Code
        }
    }
}

我們在理解上,可以將這段程式碼展開成這樣

namespace ConsoleApplication1 
{ 
    public class ClassC
    {
        public virtual void XXX()
        {
            // ClassC Code
        }

        public virtual void YYY()
        {
            // ClassC Code
        }
    }

    public class ClassD : ClassC
    {
        private ClassC base = new ClassC();

        public virtual void XXX()
        {
            // ClassD Code
        }
 
        public virtual void YYY()
        {
            base.YYY();
        }
    }
}

這段程式碼跟之前範例不同的地方在於多了virtual及override的宣告。
當我們宣告類別成員為virtual的時候,
就代表衍生的子類別,可以覆寫這個成員。


當子類別使用override關鍵字覆寫成員的時候
程式碼展開的規則,不會呼叫base的成員,
而是執行子類別撰寫的程式碼。(如上面範例的 XXX())


當然啦~ 子類別也可以選擇不覆寫父類別的成員。
程式碼展開的規則就跟一般的成員一樣,
會呼叫父類別的成員。(如上面範例的 YYY())


後記 :

本篇的文章,
描述了繼承的運作,希望對大家有幫助^^


P.S.
本篇的內容大幅度的簡化了計算機結構的內容,用以傳達物件導向的概念。
實際電腦系統在運作的時候,比本篇說明的複雜很多 ^^"。

期許自己
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。