C++ adalah bahasa pemrograman yang kuat dan berkinerja tinggi yang memberikan kontrol yang luas kepada para pengembang atas sumber daya sistem. Di antara banyak fiturnya, kata kunci final adalah tambahan yang relatif baru, diperkenalkan pada C++ 11. Kata kunci ini dapat digunakan untuk menandai kelas dan metode sebagai tidak dapat diperpanjang atau tidak dapat ditimpa, memberikan manfaat sintaksis dan kinerja. Memahami dampak kinerja dari penggunaan final dapat membantu pengembang membuat keputusan yang lebih tepat ketika merancang aplikasi C++.
Kata Kunci terakhir yang dijelaskan
Dalam C++, kata kunci final memiliki dua fungsi utama:
1. Mencegah Pewarisan: Final digunakan untuk mencegah sebuah kelas diwariskan. Ini berarti bahwa kelas tersebut tidak dapat disubkelaskan. Hal ini sangat membantu ketika membuat kelas yang tidak boleh diwarisi, baik untuk alasan desain atau keamanan.
2. Pencegahan Penimpaan Metode (untuk Metode): Final, bila diterapkan pada fungsi virtual, melarang penimpaan fungsi tersebut pada kelas turunan. Hal ini sangat membantu dalam menegakkan bahwa perilaku sebuah metode telah ditetapkan, dan subkelas tidak dapat mengubahnya.
sumber: toptal.com |
Sintaks untuk menerapkan final sangat mudah:
class Base final {// This class cannot be inherited};class Derived : public Base { // Compilation error// Error: cannot inherit from 'Base' because it is marked 'final'};
Untuk metode, final digunakan seperti ini:
class Base {public:virtual void foo() final {// Cannot be overridden in any derived class}};class Derived : public Base {public:void foo() override { // Compilation error// Error: cannot override final function}};
Manfaat Kinerja dari final
Meskipun kata kunci final lebih merupakan alat bantu desain, kata kunci ini penting dalam beberapa kasus dari sisi performa. Potensi peningkatan kinerja muncul terutama dari pengoptimalan yang diaktifkan oleh kompiler karena perilaku kelas atau metode yang diketahui.
1. Pengoptimalan Panggilan Fungsi Virtual
Ini berarti bahwa dalam pemrograman berorientasi objek, pemanggilan fungsi virtual diselesaikan pada saat runtime melalui metode yang disebut sebagai pengiriman dinamis. Cara kerjanya adalah dengan membuat setiap objek memelihara tabel virtual (vtable) yang dikonsultasikan untuk menentukan metode mana yang akan dikirim. Hal ini menimbulkan overhead yang kecil namun nyata pada setiap akses, terutama pada loop yang ketat atau bagian kode yang sangat penting untuk kinerja.
Ketika sebuah metode ditandai sebagai final, kompiler tahu bahwa tidak ada kelas turunan yang akan menimpanya. Hasilnya, kompiler dapat mengoptimalkan pencarian vtable untuk metode tertentu, mengubahnya menjadi pemanggilan langsung. Hal ini dapat menghilangkan overhead kinerja yang terkait dengan pengiriman virtual dalam kasus-kasus di mana metode tersebut diketahui sebagai final.
Sebagai contoh, perhatikan kode berikut ini:
class Base {public:virtual void foo() { /* implementation */ }};class Derived : public Base {public:void foo() override { /* derived implementation */ }};Base* b = new Derived();b->foo(); // Virtual dispatch
Pada contoh ini, foo() di Base bersifat virtual, dan pemanggilannya akan menimbulkan pencarian vtable pada saat runtime. Tetapi, jika kita menerapkan final pada foo():
class Base {
public:
virtual void foo() final { /* implementation */ }
};
Kompiler dapat mengoptimalkan pemanggilan ini dengan menghindari pengiriman virtual dan langsung memanggil foo().
2. Peluang Inline
Fungsi inline adalah sumber lain yang memungkinkan untuk meningkatkan performa. Sebuah metode yang bersifat final tidak dapat ditimpa oleh subkelas, sehingga kompiler dapat melakukan inline dengan lebih agresif. Hal ini memungkinkan kompiler untuk mengeluarkan kode yang lebih optimal dengan mengganti pemanggilan fungsi dengan badan fungsi sebaris di tempat pemanggilan, yang menghindari overhead pemanggilan itu sendiri.
Sebaliknya, metode yang bersifat virtual tidak dapat di inline dalam banyak kasus, karena kompiler tidak dapat menentukan pada saat kompilasi metode mana yang akan dipanggil (karena kemungkinan pengiriman dinamis). Dengan final, kompiler mendapatkan lebih banyak kepastian tentang perilaku metode, membuka pintu untuk pengoptimalan inline.
Pertukaran Kinerja
Meskipun pada akhirnya mengarah pada beberapa peningkatan kinerja dalam kasus tertentu, dampaknya secara keseluruhan rendah. Overhead yang terkait dengan pemanggilan fungsi virtual biasanya rendah, dan potensi manfaat kinerja dari penandaan metode atau kelas final mungkin dapat diabaikan dalam banyak aplikasi.
Meskipun demikian, kinerja sering menjadi perhatian utama bagi pengembang perangkat lunak dan dengan demikian, pengoptimalan kecil dapat menghasilkan peningkatan kinerja yang besar, terutama jika diulang berkali-kali dalam kasus aplikasi besar. Dalam kasus ini, menandai metode atau kelas sebagai final dapat membantu kompiler melakukan pengoptimalan yang lebih agresif.
Kesimpulan
Kata kunci terakhir dalam C++ menawarkan lebih dari sekadar cara untuk menerapkan batasan desain. Hal ini dapat memberikan dampak yang nyata pada kinerja dengan mengaktifkan optimasi kompiler yang mengurangi overhead panggilan fungsi virtual dan memungkinkan inlining yang lebih agresif. Meskipun peningkatan kinerja ini sering kali tidak kentara, peningkatan ini dapat menjadi sangat penting dalam aplikasi yang sangat penting untuk kinerja. Seperti biasa, pengembang harus mempertimbangkan kejelasan desain dan kinerja saat menggunakan final, memastikan bahwa manfaatnya selaras dengan tujuan program.
Kembali ke>>>> Pengujian & Kinerja