C# mengambil yang terbaik dari C++ dan Java dalam hal OOP — lebih aman dari C++ (tidak ada multiple inheritance yang membingungkan) dan lebih ekspresif dari Java (properties, pattern matching). Setelah memahami class dasar di C#, di artikel ini kita akan mempelajari bagaimana class bisa saling berhubungan melalui inheritance dan bagaimana polymorphism membuat kode menjadi lebih fleksibel.
Inheritance Dasar
// Base class
public class Kendaraan
{
public string Merk { get; protected set; }
public int Tahun { get; protected set; }
protected int Kecepatan = 0;
public Kendaraan(string merk, int tahun)
{
Merk = merk;
Tahun = tahun;
}
public virtual void Akselerasi(int tambah)
{
Kecepatan += tambah;
Console.WriteLine($"{Merk} berakselerasi ke {Kecepatan} km/h");
}
public virtual string Info() => $"{Merk} ({Tahun}) — {Kecepatan} km/h";
}
// Derived class — menggunakan : BaseClass
public class Mobil : Kendaraan
{
public int JumlahPintu { get; }
public Mobil(string merk, int tahun, int pintu)
: base(merk, tahun) // Memanggil constructor base class
{
JumlahPintu = pintu;
}
public override string Info() // override menggunakan keyword, bukan annotation
=> $"{base.Info()} | {JumlahPintu} pintu";
}
public class Motor : Kendaraan
{
public bool PunyaSidecar { get; }
public Motor(string merk, int tahun, bool sidecar = false)
: base(merk, tahun)
{
PunyaSidecar = sidecar;
}
public override void Akselerasi(int tambah)
{
base.Akselerasi(tambah); // Panggil versi base
Console.WriteLine("(Motor lebih responsif)");
}
}
// Polymorphism
var kendaraan = new List<Kendaraan>
{
new Mobil("Toyota Avanza", 2023, 4),
new Motor("Honda CBR", 2022),
new Mobil("Tesla Model 3", 2024, 4)
};
foreach (var k in kendaraan)
{
Console.WriteLine(k.Info());
}
// Output:
// Toyota Avanza (2023) — 0 km/h | 4 pintu
// Honda CBR (2022) — 0 km/h
// Tesla Model 3 (2024) — 0 km/h | 4 pintu
Abstract Class dan Method
public abstract class PembayaranDigital
{
protected string NominalStr(decimal amount)
=> $"Rp {amount:N0}";
// Abstract: WAJIB diimplementasikan oleh derived class
public abstract bool Proses(decimal jumlah);
public abstract string NamaMetode { get; }
// Non-abstract: shared logic untuk semua
public void CetakStruk(decimal jumlah, bool berhasil)
{
Console.WriteLine($"[{NamaMetode}] {NominalStr(jumlah)} — " +
(berhasil ? "✅ BERHASIL" : "❌ GAGAL"));
}
}
public class GopayPayment : PembayaranDigital
{
private decimal _saldo;
public GopayPayment(decimal saldo) => _saldo = saldo;
public override string NamaMetode => "GoPay";
public override bool Proses(decimal jumlah)
{
if (jumlah > _saldo) { CetakStruk(jumlah, false); return false; }
_saldo -= jumlah;
CetakStruk(jumlah, true);
return true;
}
}
public class KartuKreditPayment : PembayaranDigital
{
private decimal _limit;
private decimal _terpakai;
public KartuKreditPayment(decimal limit) => _limit = limit;
public override string NamaMetode => "Kartu Kredit";
public override bool Proses(decimal jumlah)
{
if (_terpakai + jumlah > _limit) { CetakStruk(jumlah, false); return false; }
_terpakai += jumlah;
CetakStruk(jumlah, true);
return true;
}
}
var metode_bayar = new List<PembayaranDigital>
{
new GopayPayment(500_000m),
new KartuKreditPayment(10_000_000m)
};
foreach (var m in metode_bayar)
m.Proses(300_000m);
// Output:
// [GoPay] Rp 300.000 — ✅ BERHASIL
// [Kartu Kredit] Rp 300.000 — ✅ BERHASIL
Interface di C#
Interface mendefinisikan kontrak tanpa implementasi — class bisa mengimplementasikan banyak interface:
public interface IDapat_Disimpan
{
void Simpan();
bool Load(int id);
}
public interface IDapat_Dicetak
{
void Cetak();
string FormatCetak { get; }
}
// Class mengimplementasikan dua interface sekaligus
public class Laporan : IDapat_Disimpan, IDapat_Dicetak
{
public string Judul { get; }
public string Isi { get; }
public Laporan(string judul, string isi)
{
Judul = judul;
Isi = isi;
}
// Implementasi IDapat_Disimpan
public void Simpan()
=> Console.WriteLine($"Menyimpan laporan: {Judul}");
public bool Load(int id)
{
Console.WriteLine($"Memuat laporan ID {id}");
return true;
}
// Implementasi IDapat_Dicetak
public string FormatCetak => "PDF";
public void Cetak()
=> Console.WriteLine($"Mencetak [{FormatCetak}]: {Judul}");
}
var laporan = new Laporan("Q1 2026", "Ringkasan kinerja...");
laporan.Simpan();
laporan.Cetak();
// Output:
// Menyimpan laporan: Q1 2026
// Mencetak [PDF]: Q1 2026
sealed — Mencegah Inheritance Lebih Lanjut
public sealed class Singleton
{
private static Singleton? _instance;
public static Singleton Instance => _instance ??= new Singleton();
private Singleton() { }
public void Lakukan() => Console.WriteLine("Singleton bekerja");
}
// public class AnakSingleton : Singleton { } // ❌ Error: cannot inherit sealed class
Pattern Matching dengan is dan switch
C# memiliki pattern matching yang powerful:
abstract class Notifikasi { }
class Email : Notifikasi { public string Penerima { get; init; } = ""; }
class SMS : Notifikasi { public string Nomor { get; init; } = ""; }
class Push : Notifikasi { public string DeviceId { get; init; } = ""; }
static void Kirim(Notifikasi notif)
{
string hasil = notif switch
{
Email e => $"Email ke {e.Penerima}",
SMS s => $"SMS ke {s.Nomor}",
Push p => $"Push ke device {p.DeviceId}",
_ => "Tipe notifikasi tidak dikenal"
};
Console.WriteLine(hasil);
}
Kirim(new Email { Penerima = "ali@email.com" });
// Output: Email ke ali@email.com
Kirim(new SMS { Nomor = "0812345678" });
// Output: SMS ke 0812345678
Pertanyaan yang Sering Diajukan
Apa perbedaan abstract class dan interface di C#?
abstract class bisa berisi implementasi (method biasa, field, constructor), sedangkan interface (sebelum C# 8) hanya berisi signature tanpa implementasi. Class hanya bisa mewarisi satu abstract class tapi bisa mengimplementasikan banyak interface. Gunakan abstract class untuk base logic bersama; gunakan interface untuk kontrak yang bisa diterapkan ke class yang tidak saling berhubungan.
Mengapa C# tidak mendukung multiple inheritance class?
Microsoft sengaja tidak mengizinkan ini untuk menghindari “diamond problem” — ambiguitas yang muncul ketika dua base class memiliki method dengan nama yang sama. Solusi yang diberikan C# adalah: gunakan interface untuk mendefinisikan kontrak yang bisa diimplementasikan oleh banyak class tanpa ambiguitas.
Apa itu sealed dan kapan menggunakannya?
sealed mencegah class di-inherit lebih lanjut. Berguna untuk: (1) keamanan — mencegah perubahan perilaku yang tidak diinginkan, (2) performa — compiler bisa mengoptimalkan karena tahu tidak ada override, (3) desain — menegaskan bahwa class tidak dirancang untuk diextend. Method juga bisa sealed untuk menghentikan override lebih lanjut di hierarki inheritance.
Kapan menggunakan base.Method() dan kapan tidak?
Panggil base.Method() saat kamu ingin menjalankan logika dari base class DAN menambahkan logika tambahan. Jangan panggil base.Method() saat kamu ingin mengganti seluruh implementasi base class. Dalam constructor, base() biasanya selalu dipanggil kecuali ada alasan kuat untuk tidak melakukannya.
Kesimpulan
| Konsep | C# | Dibanding C++ | Dibanding Java |
|---|---|---|---|
| Inheritance | : BaseClass | Sama | Sama (extends) |
| Override | virtual + override | Sama | Semua virtual default |
| Abstract | abstract keyword | = 0 (pure virtual) | abstract keyword |
| Interface | interface keyword | Pure abstract class | interface keyword |
| Sealed | sealed | final class (tidak ada) | final class |
Artikel sebelumnya: Class dan Object di C# — membuat class dasar di C#.
Langkah selanjutnya: Exception Handling di C# — cara menangani error dengan try/catch/finally.