Menu
CoddyTech

Fungsi Virtual & VTable

Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 52 dari 104.

Kata kunci virtual mengatasi masalah yang kita lihat di pelajaran sebelumnya. Saat kamu mendeklarasikan method sebagai virtual, C++ menentukan versi mana yang akan dipanggil berdasarkan tipe object sebenarnya saat program berjalan, bukan tipe pointer.

class Animal {
public:
    virtual void speak() {
        std::cout << "Some sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void speak() override {
        std::cout << "Woof!" << std::endl;
    }
};

Dog d;
Animal* ptr = &d;
ptr->speak();  // output: Woof!

Sekarang method yang benar dipanggil! Kata kunci override bersifat opsional, tetapi disarankan. Kata kunci ini memberi tahu compiler bahwa kamu bermaksud mengganti fungsi virtual, sehingga kesalahan akan terdeteksi jika tanda tangannya tidak cocok.

Bagaimana cara kerjanya? Saat sebuah class memiliki fungsi virtual, kompilator membuat tabel virtual (vtable). Tabel pencarian tersembunyi ini berisi pointer ke fungsi virtual class tersebut. Setiap object yang memiliki fungsi virtual menyimpan pointer tersembunyi (vptr) ke vtable class-nya.

Saat kamu memanggil fungsi virtual melalui pointer, program mencari alamat fungsi yang tepat di vtable saat runtime. Ini disebut dynamic dispatch. Proses ini menambahkan sedikit overhead dibandingkan pemanggilan fungsi biasa, tetapi memungkinkan perilaku polimorfik yang andal.

Satu aturan penting: jika sebuah class memiliki fungsi virtual dan akan digunakan sebagai base class, destructornya juga harus virtual. Ini memastikan pembersihan yang tepat saat menghapus object turunan melalui pointer base:

class Animal {
public:
    virtual ~Animal() {}  // Destruktor virtual
    virtual void speak() {}
};
challenge icon

Tantangan

Mudah

Mari kita buat sistem pemutar media yang menunjukkan keunggulan fungsi virtual dan polimorfisme saat runtime. Kamu akan membuat hierarki tipe media yang masing-masing diputar dengan cara berbeda, lalu melihat bagaimana fungsi virtual memungkinkan perilaku yang tepat meskipun diakses melalui pointer class dasar.

Kamu akan mengatur kodemu dalam tiga file:

  • Media.h: Definisikan class dasar Media yang mewakili media apa pun yang dapat diputar:
    • Member std::string title yang dilindungi
    • Konstruktor yang menerima judul dan menyimpannya
    • Method virtual play() yang mencetak: Playing media: <title>
    • Destructor virtual yang mencetak: Media [<title>] destroyed
  • AudioTrack.h: Definisikan class AudioTrack yang mewarisi Media secara publik:
    • Member std::string artist yang bersifat privat
    • Konstruktor yang menerima judul dan artis, meneruskan judul ke class dasar, lalu menyimpan artis
    • Override play() menggunakan kata kunci override untuk mencetak: Playing audio: <title> by <artist>
    • Destructor yang mencetak: AudioTrack [<title>] destroyed
  • main.cpp: Baca tiga input, masing-masing pada baris terpisah:
    1. Judul audio track (string)
    2. Nama artis (string)
    3. Judul video (string)

    Definisikan class VideoClip langsung di main.cpp yang mewarisi Media secara publik:

    • Member int duration yang bersifat privat, dalam satuan detik
    • Konstruktor yang menerima judul dan durasi, dengan durasi default 120
    • Override play() untuk mencetak: Playing video: <title> (<duration>s)
    • Destructor yang mencetak: VideoClip [<title>] destroyed

    Buat array berisi tiga pointer Media* di dalam cakupan blok. Alokasikan secara dinamis:

    • Sebuah object dasar Media dengan judul "Generic Media"
    • Sebuah object AudioTrack dengan judul dan artis dari input
    • Sebuah object VideoClip dengan judul video dari input

    Lakukan perulangan pada array dan panggil play() pada setiap pointer. Lalu hapus semua object dengan urutan terbalik. Setelah blok, cetak: Playback complete!

Sebagai contoh, dengan input Bohemian Rhapsody, Queen, dan Nature Documentary:

Playing media: Generic Media
Playing audio: Bohemian Rhapsody by Queen
Playing video: Nature Documentary (120s)
VideoClip [Nature Documentary] destroyed
Media [Nature Documentary] destroyed
AudioTrack [Bohemian Rhapsody] destroyed
Media [Bohemian Rhapsody] destroyed
Media [Generic Media] destroyed
Playback complete!

Perhatikan bahwa pemanggilan play() melalui pointer Media* menjalankan method class turunan yang tepat berkat fungsi virtual. Perhatikan juga bagaimana destructor virtual memastikan pembersihan yang tepat: destructor class turunan dan dasar sama-sama dijalankan saat menghapus melalui pointer dasar.

Coba sendiri

#include <iostream>
#include <string>
#include "Media.h"
#include "AudioTrack.h"

using namespace std;

// TODO: Definisikan class VideoClip di sini yang mewarisi Media secara publik
// - Anggota duration bertipe int yang bersifat private (dalam detik)
// - Konstruktor menerima title dan duration (nilai default duration adalah 120)
// - Override play() untuk mencetak: Playing video: <title> (<duration>s)
// - Destruktor mencetak: VideoClip [<title>] destroyed

class VideoClip : public Media {
private:
    int duration;

public:
    // TODO: Implementasikan konstruktor
    VideoClip(const std::string& t, int d = 120) : Media(t) {
        // TODO: Simpan duration
    }

    // TODO: Override method play()
    void play() override {
        // TODO: Implementasikan method ini
    }

    // TODO: Implementasikan destruktor
    ~VideoClip() {
        // TODO: Implementasikan destruktor ini
    }
};

int main() {
    // Baca input
    string audioTitle;
    string artist;
    string videoTitle;
    
    getline(cin, audioTitle);
    getline(cin, artist);
    getline(cin, videoTitle);

    // TODO: Buat cakupan blok dengan kurung kurawal
    // Di dalam blok:
    // 1. Buat array berisi tiga pointer Media*
    // 2. Alokasikan secara dinamis:
    //    - object Media dasar dengan judul "Generic Media"
    //    - object AudioTrack dengan judul dan artis dari input
    //    - object VideoClip dengan judul video dari input
    // 3. Ulangi setiap elemen array dan panggil play() pada tiap pointer
    // 4. Hapus semua object dalam urutan terbalik

    // TODO: Setelah blok, cetak: Playback complete!
    
    return 0;
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Object

Latihan sendiri: Compiler C++ online