Polimorfisme saat Compile vs Runtime
Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 56 dari 104.
Polymorphism berarti "banyak bentuk" dan merupakan konsep inti OOP yang memungkinkan object diperlakukan secara seragam sambil berperilaku berbeda. C++ mendukung dua jenis polymorphism yang berbeda, masing-masing diselesaikan pada tahap yang berbeda dalam eksekusi program.
Polimorfisme waktu kompilasi (juga disebut polimorfisme statis) ditentukan oleh kompiler sebelum program dijalankan. Kompiler menentukan dengan tepat fungsi mana yang akan dipanggil berdasarkan signature fungsi. Ini mencakup overloading fungsi dan template:
void print(int x) { std::cout << "Integer: " << x << std::endl; }
void print(double x) { std::cout << "Double: " << x << std::endl; }
print(5); // Compiler memilih print(int)
print(3.14); // Compiler memilih print(double)Polimorfisme saat runtime (juga disebut polimorfisme dinamis) ditentukan saat program berjalan. Keputusan tentang fungsi mana yang akan dipanggil bergantung pada tipe object sebenarnya, bukan tipe pointer atau reference. Hal ini dicapai melalui fungsi virtual:
class Shape {
public:
virtual void draw() { std::cout << "Drawing shape" << std::endl; }
};
class Circle : public Shape {
public:
void draw() override { std::cout << "Drawing circle" << std::endl; }
};
Shape* s = new Circle();
s->draw(); // Ditentukan saat program berjalan: "Drawing circle"Kompromi utamanya: polimorfisme saat kompilasi tidak memiliki overhead runtime karena keputusan dibuat selama kompilasi, sedangkan polimorfisme runtime menambah sedikit biaya (pencarian vtable), tetapi memberikan fleksibilitas lebih besar saat bekerja dengan object yang tipenya belum diketahui sampai program dijalankan.
Tantangan
MudahMari buat sistem kalkulator yang menunjukkan kedua jenis polimorfisme secara berdampingan. Kamu akan membuat sistem yang menggunakan polimorfisme waktu kompilasi untuk menangani berbagai tipe input melalui overloading fungsi, sementara polimorfisme waktu runtime memungkinkan strategi perhitungan yang berbeda ditukar secara dinamis.
Kamu akan mengatur kodemu dalam tiga file:
Calculator.h: Definisikan baseCalculatorclass yang mewakili strategi perhitungan apa pun:- Method virtual
calculate(int a, int b)yang mengembalikanintdan mencetak:Base calculation: <a> ? <b>(mengembalikan 0) - Destructor virtual
- Method virtual
Operations.h: Definisikan dua class kalkulator turunan yang menimpa perilaku perhitungan:Adder: Timpacalculate()agar mencetakAdding: <a> + <b>dan mengembalikan jumlahnyaMultiplier: Timpacalculate()agar mencetakMultiplying: <a> * <b>dan mengembalikan hasil kalinya
override.main.cpp: Buat sistem yang menunjukkan kedua jenis polimorfisme. Baca dua input bilangan bulat (masing-masing pada baris terpisah).Pertama, tunjukkan polimorfisme waktu kompilasi dengan membuat tiga fungsi
display()yang di-overload:display(int x)mencetak:Integer value: <x>display(double x)mencetak:Double value: <x>display(const std::string& x)mencetak:String value: <x>
Lalu, tunjukkan polimorfisme waktu runtime dengan membuat array berisi pointer
Calculator*yang menunjuk ke sebuahCalculatordasar, sebuahAdder, dan sebuahMultiplier. Lakukan perulangan dan panggilcalculate()pada masing-masing dengan nilai inputmu, lalu cetak hasilnya setelah setiap perhitungan.Susun outputmu seperti berikut:
=== Compile-Time Polymorphism === <display outputs for int, double, string> === Runtime Polymorphism === <calculate outputs with results>Untuk bagian waktu kompilasi, panggil
display()dengan input pertama sebagai bilangan bulat, lalu sebagai bilangan double (nilai yang sama ditambah .5), kemudian sebagai string "Result". Bersihkan kalkulator yang dialokasikan secara dinamis setelah selesai.
Contohnya, dengan input 10 dan 3:
=== Compile-Time Polymorphism ===
Integer value: 10
Double value: 10.5
String value: Result
=== Runtime Polymorphism ===
Base calculation: 10 ? 3
Result: 0
Adding: 10 + 3
Result: 13
Multiplying: 10 * 3
Result: 30Perhatikan bagaimana compiler memilih overload display() yang tepat berdasarkan tipe argumen (keputusan waktu kompilasi), sementara method calculate() yang tepat ditentukan oleh tipe object sebenarnya saat runtime melalui mekanisme vtable.
Coba sendiri
#include <iostream>
#include <string>
#include "Calculator.h"
#include "Operations.h"
// TODO: Buat tiga fungsi display() yang di-overload:
// 1. display(int x): mencetak "Integer value: <x>"
// 2. display(double x): mencetak "Double value: <x>"
// 3. display(const std::string& x): mencetak "String value: <x>"
int main() {
// Baca dua input bilangan bulat
int a, b;
std::cin >> a;
std::cin >> b;
// === Compile-Time Polymorphism ===
std::cout << "=== Compile-Time Polymorphism ===" << std::endl;
// TODO: Panggil display() dengan:
// - a sebagai bilangan bulat
// - a sebagai double (tambahkan 0.5 ke a)
// - string "Result"
std::cout << std::endl;
// === Runtime Polymorphism ===
std::cout << "=== Runtime Polymorphism ===" << std::endl;
// TODO: Buat array berisi pointer Calculator* dengan 3 elemen:
// - Calculator dasar
// - Adder
// - sebuah Multiplier
// TODO: Telusuri array dengan perulangan, lalu panggil calculate(a, b) pada setiap elemennya,
// dan cetak "Result: <return_value>" setelah setiap perhitungan
// TODO: Bebaskan memori yang dialokasikan secara dinamis
return 0;
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Object
1Dasar-Dasar OOP
File EksternalBuild dan Kompilasi C++File Header dan File SourceNamespace dan CakupanPengantar OOP dalam C++class vs objectPointer 'this'method (Fungsi Anggota)Atribut (Anggota Data)Dasar Ctor dan DtorRingkasan: Kalkulator Sederhana4Properti class
Anggota instance vs staticGetter dan setterFungsi anggota constKata kunci mutableMethod dan variabel staticFungsi dan class friendRangkuman, Pengelola Rekening Bank7Pewarisan
Pewarisan DasarTingkat Akses pada PewarisanUrutan Pemanggilan Ctor & DtorPenimpaan methodFungsi Virtual & VTablePewarisan BergandaPewarisan VirtualRangkuman: Hierarki Karyawan2Manajemen Memori
Memori Stack vs HeapPointer dan ReferenceMemori Dinamis (new/delete)Smart Pointer di C++RAII di C++Rangkuman: Pengelola Array Dinamis5Enkapsulasi
Penentu Akses dalam C++Penentu Akses secara MendalamPenyembunyian Informasistruct vs classNested dan Inner classRangkuman, Sistem Catatan Siswa8Polimorfisme
Polimorfisme saat Compile vs RuntimeOverloading FungsiMeninjau Kembali Fungsi VirtualFungsi Virtual MurniKelas AbstrakDesain Interface di C++Casting Dinamis & RTTIRangkuman: Kalkulator Bentuk3Konstruktor & Destruktor
Konstruktor DefaultKonstruktor BerparameterKonstruktor SalinKonstruktor PindahDaftar Inisialisasi KonstruktorKonstruktor DelegasiKupas Tuntas DestruktorAturan Tiga, Lima, dan NolRangkuman: class String6Overloading Operator
Pengantar Overloading OperatorOverloading Operator AritmetikaOverloading Operator PerbandinganOperator StreamOverloading Operator PenugasanOverloading Operator [] dan ()Operator Konversi TipeRingkasan, class Matrix9Template
Template FungsiTemplate classSpesialisasi TemplateTemplate VariadikDasar SFINAE & Type TraitsRangkuman, Container GenerikLatihan sendiri: Compiler C++ online