Kata kunci MustInherit dan NotInheritable mengatur dua ujung dari perluasan kelas, yaitu kelas yang wajib diwarisi sebelum digunakan dan kelas yang dilarang diwarisi sama sekali. Topik ini membahas kelas abstrak dengan MustInherit beserta anggota MustOverride-nya, kelas terkunci dengan NotInheritable, serta NotOverridable untuk menutup rantai penimpaan. Contoh yang dijalankan membangun kelas abstrak PembacaSensor dengan dua turunannya, dan pesan error compiler yang menolak pembuatan objek dari kelas abstrak ditampilkan dari eksekusi nyata.
Kelas abstrak dengan MustInherit#
Kelas yang diberi penanda MustInherit disebut kelas abstrak, yaitu kelas yang hanya dapat digunakan sebagai kelas induk dan tidak dapat diinstansiasi secara langsung. Operator New pada kelas semacam ini ditolak compiler, sehingga satu-satunya jalan menggunakannya adalah mewarisinya. Kelas abstrak cocok menjadi titik temu ketika beberapa kelas berbagi keadaan dan perilaku yang sama, tetapi satu bagian perilakunya justru harus berbeda di tiap kelas turunannya.
Berbeda dari antarmuka, kelas abstrak boleh memuat field, properti, konstruktor, dan metode yang sudah memiliki badan. Karena itu kelas PembacaSensor berikut dapat menyimpan properti Lokasi dan menyediakan metode Tampilkan yang langsung siap digunakan turunannya, sementara satu metode sengaja dibiarkan tanpa badan untuk diisi turunannya masing-masing.
MustInherit Class PembacaSensor
Public Property Lokasi As String
' MustOverride: hanya deklarasi, badannya wajib diisi kelas turunan
Public MustOverride Function BacaNilai() As Double
' metode biasa tetap boleh ada dan menggunakan hasil MustOverride
Public Sub Tampilkan()
Console.WriteLine($"{Lokasi}: {BacaNilai()}")
End Sub
End Class
Class PembacaSuhu
Inherits PembacaSensor
Public Property SuhuCelsius As Double
Public Overrides Function BacaNilai() As Double
Return SuhuCelsius
End Function
End Class
Class PembacaKelembapan
Inherits PembacaSensor
Public Property PersenKelembapan As Double
Public Overrides Function BacaNilai() As Double
Return PersenKelembapan
End Function
End Class
Module Program
Sub Main()
Dim suhu As New PembacaSuhu With {.Lokasi = "Ruang server", .SuhuCelsius = 24.5}
Dim lembap As New PembacaKelembapan With {.Lokasi = "Gudang arsip", .PersenKelembapan = 68}
suhu.Tampilkan()
lembap.Tampilkan()
End Sub
End ModuleRuang server: 24.5
Gudang arsip: 68Pemanggilan Tampilkan dilakukan pada objek PembacaSuhu dan PembacaKelembapan, sedangkan tidak ada satu pun objek PembacaSensor yang dibuat. Metode Tampilkan yang badannya ada di kelas abstrak tetap memanggil BacaNilai(), dan pemanggilan itu mendarat pada versi milik kelas objeknya, yaitu SuhuCelsius untuk sensor suhu dan PersenKelembapan untuk sensor kelembapan. Pola ini memungkinkan kelas abstrak menulis alur bersama sekali, sementara bagian yang berbeda diserahkan kepada turunannya.
Upaya membuat objek langsung dari kelas abstrak ditolak pada waktu kompilasi, seperti tampak pada fragment dan transkrip berikut.
' tidak-dijalankan
Dim pembaca As New PembacaSensor() ' error BC30569: New tidak boleh dipakai pada kelas yang dinyatakan MustInherit$ bash /home/kal/my-project/scripts/vb-build.sh /home/kal/my-project/build-scratch/oop__uji-tolak2
/home/kal/my-project/build-scratch/oop__uji-tolak2/Program.vb(14,18): error BC30569: 'New' cannot be used on a class that is declared 'MustInherit'. [/home/kal/my-project/build-scratch/oop__uji-tolak2/WinForms.vbproj]
Build FAILED.MustOverride dan kontrak yang wajib diisi#
Anggota yang diberi penanda MustOverride adalah deklarasi kepala prosedur tanpa badan, tanpa End Function, dan wajib berada di dalam kelas yang juga MustInherit. Kelas turunan wajib menimpanya dengan Overrides, dan compiler menolak kelas turunan yang masih menyisakan anggota MustOverride tanpa implementasi. Dari sudut pandang turunan, anggota ini bekerja seperti kontrak antarmuka yang menyatu dengan pewarisan kelas.
Pembagian kerja pada contoh mengikuti pola itu secara ketat. PembacaSensor menjanjikan bahwa setiap turunannya dapat dibaca melalui BacaNilai() As Double, tetapi tidak mengatur dari mana angkanya berasal. Kelas PembacaSuhu mengisinya dari properti SuhuCelsius, sedangkan kelas PembacaKelembapan mengisinya dari properti PersenKelembapan, dan penambahan jenis sensor baru di masa depan cukup mengisi kontrak yang sama. Semua turunan otomatis mendapatkan metode Tampilkan tanpa menyentuhnya lagi, sehingga aturan tampilan tidak pernah melebar ke luar kelas abstraknya.
Kelas terkunci dengan NotInheritable#
Kelas yang diberi penanda NotInheritable berada di ujung yang berlawanan, yaitu kelas siap pakai yang dilarang diwarisi. Operator New terhadapnya sah dan program dapat membuat objeknya, sedangkan pernyataan Inherits terhadap kelasnya ditolak compiler dengan pesan error BC30299. Penanda ini padanan dari konsep sealed pada bahasa .NET lainnya, dan kelas pustaka standar yang perilakunya memang final umumnya dideklarasikan dengan cara ini.
' tidak-dijalankan
NotInheritable Class Utilitas
End Class
Class TurunanUtilitas
Inherits Utilitas ' error BC30299: kelas tidak boleh mewarisi kelas yang dinyatakan NotInheritable
End ClassAlasan mengunci kelas biasanya berkaitan dengan jaminan perilaku. Kelas yang memuat aturan keamanan, fungsi matematika, atau utilitas kecil yang sudah selesai tidak memerlukan titik perluasan, sehingga melarang pewarisan mencegah turunan mengubah jaminan itu tanpa disengaja. Penanda NotOverridable menutup hal yang sama pada tingkat anggota, yaitu metode Overrides yang diberi NotOverridable tidak dapat ditimpa lagi oleh turunan berikutnya. Anggota kelas biasa tanpa Overridable sebenarnya sudah tertutup sejak awal, sehingga NotOverridable hanya relevan pada rantai penimpaan yang sedang berlangsung.
Memilih antara kelas abstrak dan kelas terkunci#
Keputusan antara MustInherit dan NotInheritable mengikuti rencana perluasan kelas. Kelas yang menyediakan alur kerja bersama tetapi menyisakan langkah yang harus berbeda per turunan dinyatakan MustInherit, dan langkah yang diserahkan itu dituliskan sebagai MustOverride. Kelas yang perilakunya sudah lengkap dan tidak dirancang untuk diperluas dinyatakan NotInheritable, sedangkan kelas biasa tanpa kedua penanda tetap dapat diwarisi sekaligus diinstansiasi.
Ketiganya bersanding dengan antarmuka pada perancangan kelas. Antarmuka menjanjikan kemampuan tanpa membagi kode apa pun, kelas abstrak membagi kode bersama sekaligus menuntut pengisian bagian yang kosong, sedangkan kelas terkunci menawarkan implementasi final tanpa janji perluasan. Kombinasi yang lazim adalah antarmuka untuk kontrak publiknya, kelas abstrak sebagai induk berisi kerangka kerjanya, dan implementasi konkret sebagai turunan yang mengisi langkah-langkahnya.
Ukuran praktisnya menyangkut dua pertanyaan, yaitu apakah kelasnya akan diperluas dan apakah sebagian perilakunya memang harus diisi turunannya. Jawaban ya untuk keduanya mengarah pada MustInherit, sedangkan jawaban tidak untuk keduanya mengarah pada NotInheritable. Kelas biasa tanpa penanda tetap menjadi pilihan tengah ketika kelasnya mungkin diperluas tetapi tidak memiliki bagian yang wajib diisi.
Kesalahan umum#
Kesalahan pertama adalah memanggil New pada kelas MustInherit, yang ditolak dengan error BC30569. Perbaikannya bukan menghilangkan penandanya, melainkan membuat objek dari kelas turunannya, karena keberadaan kelas abstrak memang disengaja agar turunannya yang diinstansiasi. Apabila kelasnya ternyata memang perlu dibuat objeknya langsung, penandanya dilepas dan anggota MustOverride-nya diberi badan.
Kesalahan kedua adalah kelas turunan yang belum menimpa seluruh anggota MustOverride induknya. Compiler menolak kelas itu dan menuntut implementasi untuk setiap anggota yang tersisa, atau apabila kelasnya memang tidak mengisinya, kelas turunan itu sendiri harus dinyatakan MustInherit agar tuntutan diteruskan ke turunan berikutnya. Pesan errornya menyebut anggota yang belum diimplementasikan, sehingga baris yang perlu dilengkapi langsung terbaca.
Kesalahan ketiga adalah mencoba mewarisi kelas NotInheritable, yang ditolak dengan error BC30299. Perbaikan yang benar menyesuaikan maksudnya, yaitu menggunakan kelasnya apa adanya melalui New, menyalin kebutuhan kecil ke kode sendiri, atau meminta kelas tersebut dibuka untuk diwarisi apabila memang dirancang ulang oleh pemiliknya. Menambahkan turunan pada kelas yang sudah final bukan perbaikan yang tersedia pada bahasanya.
Ringkasan#
- Kelas
MustInheritadalah kelas abstrak yang tidak dapat diinstansiasi, boleh memuat anggota berbadan, dan menuntut kelas turunannya mengisi anggotaMustOverridemelaluiOverrides. - Kelas
NotInheritableadalah kelas final yang boleh diinstansiasi tetapi dilarang diwarisi, sedangkanNotOverridablemenutup rantai penimpaan pada tingkat anggota. - Pemilihan keduanya mengikuti rencana perluasan, yaitu kerangka yang menuntut pengisian dengan
MustInherit, implementasi final denganNotInheritable, dan kontrak murni dengan antarmuka.
Referensi#
- MustInherit — Microsoft Learn
— Kelas abstrak, larangan
New, dan kewajiban turunannya. - NotInheritable — Microsoft Learn — Kelas final yang tidak dapat menjadi kelas induk.
- NotOverridable — Microsoft Learn — Penanda anggota yang menutup penimpaan lebih lanjut.
- Inheritance Basics — Microsoft Learn — Konteks pewarisan yang memuat kedua penanda tersebut.