Mengonfigurasi kelas dasar dan turunan
Istilah kelas dasar dan kelas turunan digunakan untuk menggambarkan hubungan antara kelas dalam hierarki warisan. Kelas dasar digunakan untuk menentukan sekumpulan atribut dan perilaku umum yang diwarisi kelas lain. Kelas turunan digunakan untuk menentukan sekumpulan atribut dan perilaku khusus yang memperluas atau memodifikasi kelas dasar.
Memeriksa sifat pewarisan transitif
Di C#, kelas hanya dapat mewarisi dari satu kelas dasar. Pembatasan ini dikenal sebagai warisan tunggal. Warisan tunggal memungkinkan kelas turunan untuk mengakses properti dan metode satu kelas dasar, mempromosikan hierarki yang jelas dan sederhana. Konsep beberapa pewarisan tidak didukung dalam C#. Pembatasan ini menghindari kompleksitas dan ambiguitas yang dapat muncul saat mewarisi dari beberapa kelas dasar. Sebagai gantinya, C# menggunakan antarmuka untuk mencapai fungsionalitas serupa.
Meskipun kelas hanya dapat mewarisi dari satu kelas dasar, warisan bersifat transitif. Ini berarti bahwa jika kelas C mewarisi dari kelas B, dan kelas B mewarisi dari kelas A, maka kelas C mewarisi anggota yang dideklarasikan di kelas B dan kelas A. Properti ini memungkinkan hierarki yang lebih dalam dan penggunaan kembali kode lebih lanjut.
Misalnya, pertimbangkan sistem manajemen kendaraan di mana Anda memiliki kelas dasar Vehicle, kelas turunan Car yang mewarisi dari Vehicle, dan kelas turunan lainnya ElectricCar yang mewarisi dari Car. Dalam hierarki ini, ElectricCar mewarisi anggota dari Car dan Vehicle, menunjukkan sifat pewarisan transitif.
public class Vehicle
{
public string Make { get; set; }
public string Model { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started.");
}
public void StopEngine()
{
Console.WriteLine("Engine stopped.");
}
}
public class Car : Vehicle
{
public int NumberOfDoors { get; set; }
public void OpenTrunk()
{
Console.WriteLine("Trunk opened.");
}
public void HonkHorn()
{
Console.WriteLine("Horn honked.");
}
public void LockDoors()
{
Console.WriteLine("Doors locked.");
}
}
public class ElectricCar : Car
{
public int BatteryCapacity { get; set; }
public void ChargeBattery()
{
Console.WriteLine("Battery charging.");
}
public void DisplayBatteryStatus()
{
Console.WriteLine("Battery status displayed.");
}
}
public class CombustionEngineCar : Car
{
public int FuelCapacity { get; set; }
public void Refuel()
{
Console.WriteLine("Car refueled.");
}
public void CheckOilLevel()
{
Console.WriteLine("Oil level checked.");
}
}
Contoh ini menunjukkan sistem manajemen kendaraan sederhana dengan kelas berikut:
kelas
Vehicle: Kelas dasarVehicleberisi properti dan metode umum untuk semua kendaraan, seperti Make, Model, StartEngine, dan StopEngine.kelas
Car: KelasCarmewarisi dariVehicledan menambahkan properti dan metode tertentu untuk mobil, sepertiNumberOfDoors,OpenTrunk,HonkHorn, danLockDoors.kelas
ElectricCar: KelasElectricCarmewarisi dariCardan menambahkan properti dan metode khusus untuk mobil listrik, sepertiBatteryCapacity,ChargeBattery, danDisplayBatteryStatus.kelas
CombustionEngineCar: KelasCombustionEngineCarjuga mewarisi dariCardan menambahkan properti dan metode khusus untuk mobil mesin pembakaran, sepertiFuelCapacity,Refuel, danCheckOilLevel.
Dalam contoh ini, kelas Car mewarisi anggota dari kelas Vehicle, dan ElectricCar dan CombustionEngineCar mewarisi anggota dari kelas Car. Hierarki ini menunjukkan sifat pewarisan transitif, di mana ElectricCar dan CombustionEngineCar mewarisi anggota dari Car dan Vehicle.
Memeriksa warisan dan visibilitas anggota
Saat kelas mewarisi dari kelas dasar, aturan berikut berlaku:
- Konstruktor statis dan instans tidak diwariskan.
- Semua anggota lain dari kelas dasar diwariskan, tetapi pengubah akses memengaruhi visibilitas mereka di kelas turunan. Pengubah akses meliputi:
public,protected,internal, danprivate.
Anggota publik
Anggota publik dapat diakses dari kode apa pun yang memiliki akses ke kelas. Kelas turunan mewarisi anggota publik dan dapat diakses dari luar hierarki kelas.
public class BaseClass
{
public int publicField;
public void PublicMethod() { }
}
public class DerivedClass : BaseClass
{
public void AccessPublicMember()
{
publicField = 10;
PublicMethod();
}
}
Dalam contoh ini, DerivedClass mewarisi anggota publicField dan PublicMethod dari BaseClass. Metode AccessPublicMember dalam DerivedClass dapat mengakses anggota ini. Anggota publik juga dapat diakses dari kode yang berada di luar hierarki kelas.
Anggota yang dilindungi
Anggota yang dilindungi dapat diakses dalam kelas tempat mereka dideklarasikan dan dalam kelas turunan. Mereka tidak dapat diakses dari luar hierarki kelas.
public class BaseClass
{
protected int protectedField;
protected void ProtectedMethod() { }
}
public class DerivedClass : BaseClass
{
public void AccessProtectedMember()
{
protectedField = 10;
ProtectedMethod();
}
}
Dalam contoh ini, DerivedClass mewarisi anggota protectedField dan ProtectedMethod dari BaseClass. Metode AccessProtectedMember dalam DerivedClass dapat mengakses anggota ini. Namun, jika Anda mencoba mengakses anggota yang dilindungi dari luar hierarki kelas, kesalahan waktu kompilasi dihasilkan.
Anggota internal
Anggota internal dapat diakses dalam rakitan yang sama. Mereka tidak dapat diakses dari luar assembly, bahkan jika kelas diwariskan.
public class BaseClass
{
internal int internalField;
internal void InternalMethod() { }
}
public class DerivedClass : BaseClass
{
public void AccessInternalMember()
{
internalField = 10;
InternalMethod();
}
}
Dalam contoh ini, DerivedClass mewarisi anggota internalField dan InternalMethod dari BaseClass. Metode AccessInternalMember dalam DerivedClass dapat mengakses anggota ini karena mereka berada dalam rakitan yang sama. Namun, jika Anda mencoba mengakses anggota internal dari luar rakitan, kesalahan waktu kompilasi dihasilkan.
Anggota privat
Anggota privat hanya dapat diakses dalam kelas tempat mereka dideklarasikan. Kelas turunan tidak mewarisi anggota privat, sehingga tidak dapat diakses langsung di kelas turunan.
public class BaseClass
{
private int privateField;
private void PrivateMethod() { }
}
public class DerivedClass : BaseClass
{
public void AccessPrivateMember()
{
// Can't access privateField or PrivateMethod
}
}
Dalam contoh ini, DerivedClass mewarisi dari BaseClass, tetapi tidak dapat mengakses anggota privateField atau PrivateMethod karena mereka privat.
Memeriksa penggunaan kata kunci abstrak, virtual, dan tersegel di kelas dasar
Kelas dasar dan turunan menggunakan kata kunci abstract, virtual, dan sealed untuk mengontrol perilaku anggota yang diwariskan. Kata kunci ini memungkinkan Anda menentukan tingkat kontrol yang dimiliki kelas turunan atas anggota kelas dasar.
Memeriksa penggunaan kata kunci abstract
Kata kunci abstract di C# digunakan untuk menentukan kelas dan anggota kelas yang tidak lengkap dan harus diimplementasikan dalam kelas turunan. Kelas abstrak tidak dapat dibuat secara langsung dan dimaksudkan untuk menjadi kelas dasar untuk kelas lain. Metode dan properti abstrak dinyatakan tanpa implementasi apa pun dan harus ditimpa dalam kelas turunan nonabstrak.
Misalnya:
public abstract class Shape
{
public abstract int GetArea();
}
public class Square : Shape
{
private int _side;
public Square(int side)
{
_side = side;
}
public override int GetArea()
{
return _side * _side;
}
}
class Program
{
static void Main()
{
Square square = new Square(5);
Console.WriteLine($"Area of the square = {square.GetArea()}");
}
}
Dalam contoh ini, kelas Shape abstrak dan berisi metode abstrak GetArea. Kelas Square mewarisi dari Shape dan menyediakan implementasi untuk metode GetArea. Kelas Square dapat diinstansiasi, dan metode GetArea mengembalikan area persegi.
Aturan berikut menjelaskan bagaimana kata kunci abstract memengaruhi pewarisan:
- Kelas abstrak: Kelas abstrak tidak dapat diinstansiasi secara langsung. Kelas abstrak adalah kelas dasar untuk kelas turunan dan kelas turunan harus memberikan implementasi untuk semua anggota abstrak kelas abstrak.
- Metode abstrak: Metode abstrak dinyatakan tanpa implementasi apa pun di kelas abstrak. Kelas turunan harus mengambil alih metode ini dan memberikan implementasi.
- Properti abstrak: Mirip dengan metode abstrak, properti abstrak dinyatakan tanpa implementasi dan harus ditimpa dalam kelas turunan.
Kata kunci abstract di C# adalah alat yang ampuh untuk menentukan kelas dan anggota yang tidak lengkap yang harus diimplementasikan dalam kelas turunan. Ini memberlakukan kontrak yang harus diikuti kelas turunan, memastikan bahwa metode dan properti tertentu diimplementasikan. Penggunaan kata kunci abstract yang sesuai mempromosikan delineasi tanggung jawab yang jelas antara kelas dasar dan turunan.
Memeriksa penggunaan kata kunci virtual
Kata kunci virtual di C# digunakan untuk menentukan metode dan properti yang dapat ditimpa dalam kelas turunan. Metode atau properti virtual memiliki implementasi di kelas dasar, tetapi dapat diperpanjang atau dimodifikasi dalam kelas turunan. Kelas turunan dapat mengambil alih anggota virtual untuk menyediakan implementasi mereka sendiri.
Misalnya:
public class Animal
{
public virtual void MakeSound()
{
Console.WriteLine("Animal makes a sound");
}
}
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Dog barks");
}
}
class Program
{
static void Main()
{
Animal animal = new Dog();
animal.MakeSound();
}
}
Dalam contoh ini, kelas Animal menentukan metode virtual MakeSound yang mencetak pesan generik. Kelas Dog mewarisi dari Animal dan mengambil alih metode MakeSound untuk mencetak pesan tertentu. Saat Anda membuat objek Dog dan memanggil metode MakeSound, implementasi yang ditimpa di kelas Dog dijalankan.
Aturan berikut menjelaskan bagaimana kata kunci virtual memengaruhi pewarisan:
- Metode virtual: Metode virtual memiliki implementasi di kelas dasar, tetapi dapat ditimpa dalam kelas turunan.
- Properti virtual: Mirip dengan metode virtual, properti virtual memiliki implementasi di kelas dasar dan dapat ditimpa dalam kelas turunan.
Memeriksa penggunaan kata kunci sealed
Kata kunci sealed di C# digunakan untuk mencegah anggota kelas atau kelas diwariskan atau ditimpa. Saat kelas ditandai sebagai sealed, kelas tersebut tidak dapat digunakan sebagai kelas dasar untuk kelas lain. Ketika metode ditandai sebagai sealed, metode tidak dapat ditimpa dalam kelas turunan.
Misalnya:
public class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Method1 in BaseClass");
}
public virtual void Method2()
{
Console.WriteLine("Method2 in BaseClass");
}
}
public class DerivedClass : BaseClass
{
public sealed override void Method1()
{
Console.WriteLine("Method1 in DerivedClass");
}
public override void Method2()
{
Console.WriteLine("Method2 in DerivedClass");
}
}
public class FinalClass : DerivedClass
{
// This class can't override Method1 because it's sealed in DerivedClass
public override void Method2()
{
Console.WriteLine("Method2 in FinalClass");
}
}
Dalam contoh ini, DerivedClass mewarisi dari BaseClass dan mengambil alih metode Method1, menandainya sebagai sealed. Metode Method2 juga ditimpa dalam DerivedClass tetapi tidak disegel.
FinalClass mewarisi dari DerivedClass dan mencoba mengambil alih metode Method2. Namun, metode ini tidak dapat mengambil alih metode Method1 karena disegel dalam DerivedClass.
Aturan berikut menjelaskan bagaimana kata kunci sealed memengaruhi pewarisan:
- Kelas yang disegel: Kelas yang disegel tidak dapat digunakan sebagai kelas dasar untuk kelas lain. Ini mencegah warisan dari kelas yang disegel.
- Metode tersegel: Metode yang disegel tidak dapat ditimpa dalam kelas turunan. Ini mencegah modifikasi lebih lanjut dari metode dalam kelas turunan.
- Properti tersegel: Mirip dengan metode yang disegel, properti yang disegel tidak dapat ditimpa dalam kelas turunan.
Kelas dan metode yang disegel berguna ketika Anda ingin mencegah ekstensi atau modifikasi lebih lanjut dari kelas atau metode. Mereka menyediakan cara untuk membatasi warisan dan memastikan bahwa anggota tertentu tetap tidak berubah.
Memeriksa pewarisan implisit dari Objek
Di C#, semua kelas secara implisit mewarisi dari kelas Object. Kelas Object menentukan beberapa metode yang tersedia untuk semua kelas, seperti ToString, Equals, dan GetHashCode. Jika kelas tidak secara eksplisit mewarisi dari kelas lain, kelas tersebut masih mewarisi dari Object secara default.
-
ToString: MetodeToStringmengembalikan string yang mewakili objek saat ini. Secara default, ini mengembalikan nama kelas yang sepenuhnya memenuhi syarat. -
Equals: MetodeEqualsmembandingkan dua objek untuk kesetaraan. Secara default, ini membandingkan referensi objek. -
GetHashCode: MetodeGetHashCodemengembalikan kode hash untuk objek saat ini. Secara default, ini mengembalikan kode hash referensi objek.
Pertimbangkan sampel kode berikut yang membuat tiga objek Person dan menunjukkan metode ToString, Equals, dan GetHashCode yang diwariskan:
Person person1 = new Person { Name = "Alice", Age = 30 };
Person person2 = new Person { Name = "Alice", Age = 30 };
Person person3 = person1;
Console.WriteLine(person1.ToString());
Console.WriteLine(person1.Equals(person2));
Console.WriteLine(person1.GetHashCode());
Console.WriteLine(person1.Equals(person3));
public class Person
{
public string? Name { get; set; }
public int Age { get; set; }
}
public class Employee : Person
{
public int EmployeeNumber { get; set; }
public decimal Salary { get; set; }
}
// Output: Person
// False
// 32854180
// True
Dalam sampel kode ini, metode ToString mengembalikan nama kelas Person yang sepenuhnya memenuhi syarat, yang mencakup namespace yang ditentukan. Metode Equals pertama membandingkan referensi objek person1 dan person2 dan mengembalikan False. Metode GetHashCode mengembalikan kode hash referensi objek person1. Dan kemudian metode Equals membandingkan referensi objek person1 dan person3 dan mengembalikan True.
Ringkasan
Pewarisan memungkinkan kelas turunan untuk mewarisi anggota kelas dasar yang menentukan sekumpulan atribut dan perilaku umum. Kelas turunan dapat memperluas atau memodifikasi perilaku kelas dasar dengan menambahkan anggota baru atau menimpa anggota yang ada. Kata kunci abstract, virtual, dan sealed digunakan untuk mengontrol bagaimana anggota kelas dasar diwariskan atau ditimpa. Visibilitas anggota yang diwariskan dipengaruhi oleh pengubah akses, seperti public, protected, internal, dan private. Semua kelas di C# secara implisit mewarisi dari kelas Object, yang menyediakan beberapa metode, seperti ToString, Equals, dan GetHashCode, yang tersedia untuk semua kelas.