Memakai Ulang Class dengan Memperluasnya
Kamu sudah membuat class dengan constructor dan membersihkannya dengan destructor. Pewarisan adalah langkah berikutnya: daripada menyalin member satu class ke class lain, kamu menyatakan bahwa class baru adalah versi khusus dari class yang sudah ada, dan membiarkannya mewarisi semuanya secara otomatis.
Class yang sudah ada disebut base class (atau induk); class yang baru disebut derived class (atau turunan). Derived class dimulai dengan semua data dan perilaku milik base class, lalu menambahkan atau mengubah apa yang membuatnya berbeda. Inilah alat utama C++ untuk hubungan "is-a": sebuah Dog adalah Animal, sebuah SavingsAccount adalah BankAccount.
Sintaks Dasar: class Derived : public Base
Kamu mewarisi dengan menulis titik dua setelah nama derived class, lalu access specifier, lalu nama base class. Bentuk yang paling umum adalah pewarisan public.
Dog tidak pernah mendeklarasikan name atau eat(), tetapi keduanya berfungsi pada objek Dog karena diwarisi dari Animal. Derived class bebas menambahkan member seperti bark() yang sama sekali tidak diketahui base class.
protected: Member Khusus untuk Turunan
Member private milik base class tidak bisa diakses di dalam derived class; pewarisan tidak merusak enkapsulasi. Kalau kamu ingin bagian dalam base class tersembunyi dari dunia luar tetapi tersedia bagi subclass, pakai access specifier protected.
Bayangkan ketiga level itu sebagai lingkaran konsentris: private berarti "hanya class ini," protected berarti "class ini dan turunannya," dan public berarti "semua orang." Lihat access-specifiers untuk gambaran lengkapnya.
Urutan Constructor dan Destructor
Objek turunan berisi subobjek base, dan bagian base itu harus sudah hidup sebelum bagian turunannya dibangun. Jadi pembuatan dimulai dari base, penghancuran dimulai dari turunan (persis kebalikannya). Kalau base class butuh argumen constructor, kamu meneruskannya lewat member initializer list.
Output-nya membuat urutan itu jadi konkret:
Animal ctor: Rex // base built first
Dog ctor // then the derived part
Dog dtor // destroyed in reverse...
Animal dtor: Rex // ...base last
Kalau kamu lupa : Animal(n) dan base class tidak punya default constructor, kodenya tidak akan bisa dikompilasi, karena C++ tidak tahu cara membangun bagian base-nya. Base class yang ingin kamu turunkan hampir selalu sebaiknya mendeklarasikan destructor (dan, seperti yang ditunjukkan halaman berikutnya, sering kali destructor virtual).
Overriding: Mendefinisikan Ulang Method Base Class
Derived class bisa mengganti method yang diwarisi dengan mendeklarasikan method bersignature sama. Kamu tetap bisa menjangkau versi aslinya lewat Base::method().
Ini hanya name hiding biasa, bukan polimorfisme: describe() mana yang berjalan ditentukan saat kompilasi berdasarkan tipe statis variabelnya. Itu batasan yang penting: kalau kamu memanggil lewat Shape& atau Shape* yang sebenarnya menunjuk ke Circle, kamu tetap mendapat Shape::describe(). Untuk memperbaikinya dibutuhkan virtual, topik halaman berikutnya.
Waspadai Object Slicing
Karena referensi atau pointer base bisa merujuk ke objek turunan, ada godaan untuk menyalin objek turunan ke variabel bertipe base. Jangan lakukan: bagian turunannya akan terpotong.
a adalah Animal sungguhan, bukan Dog yang memakai label base, jadi breed memang tidak ada padanya. Untuk bekerja dengan objek turunan secara polimorfik, kamu harus memakai referensi base (Animal&) atau pointer base (Animal*), jangan pernah nilai base. Slicing terjadi diam-diam: kodenya berhasil dikompilasi dan datanya hilang begitu saja. Karena itulah slicing termasuk bug pewarisan yang paling mudah lolos ke produksi.
Kesalahan Umum yang Perlu Dihindari
- Mengira member
privatemilik base bisa dijangkau di turunan. Tidak bisa. Pakaiprotecteduntuk data yang memang dibutuhkan derived class, dan jaga keadaan yang benar-benar internal tetapprivate. - Lupa meneruskan argumen constructor base. Kalau base class tidak punya default constructor, kamu harus memanggilnya secara eksplisit di initializer list constructor turunan (
: Base(args)). - Memotong objek turunan menjadi nilai base. Menyalin
DogkeAnimalmembuang semua yang khasDog. Teruskan dan simpan referensi atau pointer base saja. - Terlalu sering memakai pewarisan untuk memakai ulang kode. Pewarisan memodelkan "is-a". Kalau hubungannya sebenarnya "has-a" (sebuah
CarpunyaEngine), utamakan komposisi, yaitu objek sebagai member, daripada pewarisan.
Berikutnya: Virtual Function
Override yang baru kamu lihat ditentukan saat kompilasi, jadi memanggil lewat pointer base mengabaikan versi turunannya. Halaman berikutnya, virtual-functions, memperkenalkan kata kunci virtual dan override: mekanisme yang membuat tipe saat program berjalan menentukan method mana yang dijalankan, membuka polimorfisme yang sesungguhnya, dan menjelaskan kenapa base class butuh virtual destructor.
Pertanyaan yang sering diajukan
Apa itu inheritance di C++?
Inheritance (pewarisan) membuatmu bisa mendefinisikan class baru (derived class) berdasarkan class yang sudah ada (base class). Derived class otomatis mendapat data member dan member function milik base class, dan bisa menambahkan yang baru atau mengganti perilaku yang sudah ada. Pewarisan memodelkan hubungan "is-a" (sebuah Dog adalah Animal) dan merupakan cara utama C++ memakai ulang serta memperluas kode di sepanjang hierarki class.
Apa perbedaan pewarisan public dan private di C++?
Dengan pewarisan public (class Dog : public Animal), antarmuka public milik base class tetap public di derived class, jadi sebuah Dog adalah Animal dan bisa dipakai di mana pun Animal diharapkan. Dengan pewarisan private, member yang diwarisi menjadi private: derived class memakai ulang implementasi base class, tetapi tidak bisa menggantikannya. Pewarisan public adalah kasus yang jauh lebih umum; pakai private hanya untuk pemakaian ulang berupa "diimplementasikan dengan memakai" class lain.
Dengan urutan apa constructor dan destructor berjalan dalam pewarisan C++?
Constructor berjalan mulai dari base: base class dibangun sepenuhnya sebelum isi constructor turunan dijalankan. Destructor berjalan dengan urutan yang persis terbalik: turunan dulu, lalu base. Ini menjamin bahwa selama objek turunan dibangun atau dibongkar, setiap bagian yang ia andalkan sudah ada (atau masih ada).