iT邦幫忙

0

【C#學習筆記】08《類別(Class)》引用、繼承

  • 分享至 

  • xImage
  •  

這篇筆記會接續上一篇的內容,繼續講解類別相關的觀念與功能。
附註,避免文章過於冗長,少數範例程式碼有些並不是完整貼上,敬請見諒!
有些會根據 上一篇遊戲情境式範例做擷取或修改,歡迎參考。


【C#學習筆記】07《類別(Class)》
【C#學習筆記】09《類別(Class)》函式多載、靜態成員


成員引用

在類別之中,成員與成員之間可以互相引用,不需要透過類別名稱.成員進行呼叫。

 public void Move() // 玩家移動
 {
     Console.WriteLine($"{Name} is moving.");
 }

 public void AttackEnemy() // 玩家攻擊
 {
     Move();//直接呼叫
     Console.WriteLine($"{Name} attacks enemy!");
 }

繼承(Inheritance)

繼承允許一個新類別(子類別)自動擁有另一個現有類別(父類別)的屬性和方法,目的在於減少重複程式碼,建立清晰的資料階層關係。用「動物」與「特定動物」的關係來解釋,父類別(基底類別Base Class):動物(Animal)及子類別(衍生類別 Derived Class):狗(Dog)動物具有年齡、體重、叫聲、吃東西等屬性及行為,而直接繼承這些特徵,不需要重新編寫「年齡」或「呼吸」的程式碼,並能進一步擴充自己專屬的「品種」與「汪汪叫」。
父類別(基底類別Base Class):動物(Animal)

namespace Class_02;

public class Animal
{
    public string Name;
    public int Age { get; set; } = 0;

    public void Eat()
    {
        Console.WriteLine($"{Name} is eating");
    }

    public void MakeSound()
    {
        Console.WriteLine($"{Name} makes a sound");
    }
}

子類別(衍生類別Derived Class):狗(Dog)

namespace Class_02;

public class Dog : Animal
{
    public Dog()
    {
        Name = "Dog";
    }

    public Dog(string name, int age)
    {
        Name = name;
        Age = age;
    }

}
using Class_02;

var dog1 = new Dog("Kevin", 3);

dog1.MakeSound("Bark Bark Bark");

virtul && override

在C#裡,virtualoverride是用來做「多型(Polymorphism)」的核心機制,讓子類別可以改寫父類別的行為。
virtual:父類別先定義「這個功能之後可以被改寫」。
override:子類別實際把它改掉

沒有繼承的情況下 ,當父類別與子類別都共同擁有MakeSound這個方法成員
父類別

namespace Class_02;

public class Animal
{
    public string Name;
    public int Age { get; set; } = 0;

    public void Eat()
    {
        Console.WriteLine($"{Name} is eating");
    }

    public void MakeSound()
    {
        Console.WriteLine($"null");
    }
}

子類別

namespace Class_02;

public class Dog : Animal
{
    public Dog()
    {
        Name = "Dog";
    }

    public Dog(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public void MakeSound()
    {
        Console.WriteLine("Bark Bark Bark");
    }

}
namespace Class_02;

public class Cat : Animal
{
    public Cat()
    {
        Name = "Dog";
    }

    public Cat(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public void MakeSound()
    {
        Console.WriteLine("Meow Meow Meow");
    }

}

使用foreach依序呼叫

using Class_02;

var beast = new Animal();
var dog1 = new Dog("Kevin", 3);
var cat1 = new Cat("Mittens", 2);

dog1.MakeSound();// Output: Bark Bark Bark
cat1.MakeSound();// Output: Meow Meow Meow

Animal[] animals = { beast, dog1, cat1 };
foreach (var animal in animals)
{
    animal.MakeSound();
}

結果顯示,獨立使用.MakeSound跟foreach呼叫的.MakeSound結果不同。foreach會顯示null,這是因為所有子類別都是繼承父類別的MakeSound

加上virtualoverride後的完整程式碼:

namespace Class_02;

public class Animal
{
    public string Name;
    public int Age { get; set; } = 0;

    public void Eat()
    {
        Console.WriteLine($"{Name} is eating");
    }

    public virtual void MakeSound()
    {
        Console.WriteLine($"null");
    }
}
namespace Class_02;

public class Dog : Animal
{
    public Dog()
    {
        Name = "Dog";
    }

    public Dog(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public override void MakeSound()
    {
        Console.WriteLine("Bark Bark Bark");
    }

}
namespace Class_02;

public class Cat : Animal
{
    public Cat()
    {
        Name = "Dog";
    }

    public Cat(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public override void MakeSound()
    {
        Console.WriteLine("Meow Meow Meow");
    }

}
using Class_02;

var beast = new Animal();
var dog1 = new Dog("Kevin", 3);
var cat1 = new Cat("Mittens", 2);

dog1.MakeSound();// Output: Bark Bark Bark
cat1.MakeSound();// Output: Meow Meow Meow

Animal[] animals = { beast, dog1, cat1 };
foreach (var animal in animals)
{
    animal.MakeSound();
}

存取修飾詞(Access Modifier)-private、public、protected

privatepublicprotected是C#的「存取修飾詞(Access Modifier)
public = 對外公開,任何地方都能存取。
private = 只有自己能用,通常用於不希望外部亂改資料。
protected = 外部不能用,但子類別可以用,是「繼承」很重要的修飾詞。

根據上述範例,我們將父類別的MakeSound方法成員改成protected,我們會發現以下這行會報錯。
這是因為參數animal並不存在於父子類別之中,因此無法使用。

foreach (var animal in animals)
{
    animal.MakeSound();//error
}

以上三種,基本上就是常用的存取修飾詞,另外還有欄位修飾詞(Field Modifier)將會在後續章節提及!


繼承(Inheritance)的使用,會提高整體專案的關聯性及可閱讀性,為後續的開發及維護提供清晰的程式碼結構。然而,這也可能讓程式碼間的耦合度(Tight Coupling)大幅提高,使得父類別與子類別之間產生強烈的依賴關係。當父類別的底層邏輯發生變更時,往往會引發「牽一髮而動全身」的連帶錯誤,進而破壞系統的封裝性並增加重構的難度,須謹慎設計架構,才能在結構清晰與架構彈性之間取得最佳平衡。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言