
Foto oleh Jorge Jesus via Pexels
Inheritance (pewarisan) adalah mekanisme OOP yang memungkinkan sebuah class baru (class turunan atau derived class) mewarisi property dan method dari class yang sudah ada (class induk atau base class), memungkinkan penggunaan ulang kode tanpa perlu menulis ulang logika yang sama.
Konsep ini sangat berguna ketika beberapa class memiliki kesamaan karakteristik namun juga memiliki perbedaan tertentu, misalnya class Mobil dan Motor yang sama-sama merupakan Kendaraan namun memiliki jumlah roda dan cara kerja yang berbeda.
Artikel ini membahas cara menerapkan inheritance di C# menggunakan kata kunci base class dan kata kunci override, termasuk penggunaan kata kunci base untuk memanggil implementasi dari class induk, serta kapan inheritance menjadi pilihan desain yang tepat.
Mendefinisikan Base Class dan Derived Class
Mobil mewarisi property dan method dari Kendaraan
Override Method dengan Kata Kunci virtual dan override
Override mengganti implementasi method dari class induk
Memanggil Implementasi Base Class dengan base
Kata kunci base memanggil implementasi dari class induk
Sealed Class untuk Mencegah Pewarisan Lebih Lanjut
Sealed class mencegah class lain mewarisinya
Memanggil Method Parent Class dengan Kata Kunci base
Kata kunci base memanggil implementasi method milik parent class
Selain dipakai untuk memanggil constructor parent, kata kunci base juga dapat dipakai untuk memanggil implementasi method milik parent class dari dalam method yang sama pada class turunan yang sudah di-override. Pada contoh di atas, method Deskripsi() pada class Mobil tidak sepenuhnya menggantikan logika parent, melainkan memperluasnya dengan menambahkan teks tambahan setelah memanggil base.Deskripsi().
Pola ini sangat berguna ketika class turunan ingin menambahkan perilaku baru tanpa menduplikasi seluruh logika yang sudah ada pada parent class, sehingga perubahan pada implementasi parent akan otomatis terbawa ke semua class turunan yang memanggil base tanpa perlu mengubah kode di masing-masing turunan satu per satu.
Inheritance pada C# hanya mendukung single inheritance untuk class, artinya satu class hanya boleh mewarisi dari satu parent class saja, berbeda dengan interface yang bisa diimplementasikan lebih dari satu sekaligus. Keterbatasan ini sengaja dirancang untuk menghindari masalah diamond problem yang umum terjadi pada bahasa yang mendukung multiple inheritance penuh seperti C++.
Sealed Class dan Sealed Method untuk Membatasi Inheritance
Class sealed tidak bisa diturunkan lagi oleh class manapun
Kata kunci sealed yang diterapkan pada deklarasi class, seperti NotifikasiSms di atas, mencegah class tersebut diwarisi oleh class lain manapun, sehingga percobaan membuat class turunan darinya akan langsung ditolak compiler pada tahap kompilasi. Pembatasan ini umumnya diterapkan pada class yang desainnya sudah dianggap final dan tidak dimaksudkan untuk diperluas lebih jauh, guna mencegah penyalahgunaan inheritance yang dapat merusak invariant atau asumsi penting yang dijaga oleh class tersebut.
Selain pada level class, kata kunci sealed juga dapat diterapkan pada method hasil override di dalam class turunan, yang berarti method tersebut sudah final pada level hierarki tersebut dan tidak dapat di-override lagi oleh class turunan berikutnya meskipun class induknya sendiri tidak sealed secara keseluruhan. Pola ini memberi kontrol lebih presisi dibanding men-sealed seluruh class, karena hanya method tertentu yang dibatasi sementara method lain tetap bisa di-override oleh turunan selanjutnya.
Dari sisi performa, JIT compiler terkadang dapat melakukan optimisasi tambahan terhadap pemanggilan method pada sealed class, karena kepastian bahwa tidak akan ada override lebih lanjut memungkinkan penghilangan sebagian overhead dynamic dispatch yang biasanya diperlukan untuk method virtual. Class seperti string pada .NET sendiri bersifat sealed, memastikan perilakunya konsisten dan tidak bisa dimodifikasi lewat inheritance oleh kode pihak ketiga manapun. Sealed juga sering dipakai sebagai keputusan desain defensif pada library publik, karena setelah dirilis dan dipakai banyak konsumen, mengizinkan inheritance pada class yang semula sealed jauh lebih aman dilakukan di kemudian hari dibanding mencabut kemampuan inheritance yang sudah terlanjur dipakai oleh banyak kode eksternal.
Perbedaan Virtual dan Abstract Member pada Inheritance
Member abstract dideklarasikan tanpa isi implementasi sama sekali dan wajib di-override oleh setiap class turunan non-abstract, seperti method Suara() pada contoh di atas yang memaksa setiap jenis kendaraan mendefinisikan suaranya sendiri sesuai karakteristiknya masing-masing. Class yang memiliki member abstract otomatis harus dideklarasikan sebagai abstract class dan tidak bisa diinstansiasi langsung dengan kata kunci new, karena dianggap belum lengkap implementasinya sampai semua anggota abstract-nya diimplementasikan oleh class turunan.
Member virtual berbeda karena sudah memiliki implementasi default pada class induk, seperti Deskripsi() yang mengembalikan teks umum, dan class turunan boleh memilih untuk meng-override-nya atau tetap memakai perilaku bawaan tanpa dipaksa sama sekali. Pola ini cocok ketika sebagian besar class turunan memiliki perilaku yang sama dan cukup memakai implementasi induk, namun beberapa di antaranya membutuhkan penyesuaian khusus sesuai kebutuhan masing-masing jenis objek turunan tersebut, tanpa harus menulis ulang seluruh logika dari awal.
Kesalahan Umum yang Sering Terjadi
Menggunakan Inheritance untuk Relasi yang Bukan 'Is-A'
Inheritance hanya tepat dipakai ketika hubungan antar class benar-benar bersifat 'is-a', misalnya Mobil adalah Kendaraan; memaksakan inheritance untuk relasi yang sebenarnya lebih cocok sebagai komposisi akan menghasilkan desain yang janggal dan sulit dipelihara.
Lupa Menandai Method dengan virtual di Base Class
Method yang tidak ditandai virtual di base class tidak bisa di-override oleh class turunan meski ditulis dengan kata kunci new, yang perilakunya berbeda (method hiding, bukan overriding sesungguhnya) dan sering membingungkan pemula.
Membuat Hierarki Inheritance Terlalu Dalam
Hierarki inheritance dengan banyak tingkatan (misalnya A mewarisi B, B mewarisi C, C mewarisi D) membuat kode sulit dilacak dan dipahami, karena perilaku sebuah object bisa berasal dari banyak tingkat yang berbeda sekaligus.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Inheritance memberikan penggunaan ulang kode yang kuat untuk class yang memang memiliki hubungan hierarkis jelas, namun ikatan yang terlalu erat antara base class dan derived class bisa membuat perubahan pada base class berdampak luas ke semua turunannya secara tidak terduga.
Sebagai alternatif, komposisi (menggabungkan object lain sebagai property, bukan mewarisinya) sering dianggap lebih fleksibel untuk kasus yang bukan benar-benar relasi is-a, mengikuti prinsip populer 'favor composition over inheritance' dalam desain software modern.
Ringkasan
Inheritance memungkinkan class turunan mewarisi dan memperluas perilaku dari class induk, dengan virtual dan override sebagai mekanisme untuk mengganti implementasi tertentu. Gunakan inheritance hanya untuk relasi is-a yang jelas, dan pertimbangkan komposisi sebagai alternatif ketika hubungan antar class tidak benar-benar bersifat hierarkis.
Seri Belajar C# Fundamental:
← Sebelumnya: Encapsulation dalam OOP C# Secara Mendalam
→ Selanjutnya: Polymorphism dengan Override dan Overload