Menu
CoddyTech

Meninjau Kembali Fungsi Virtual

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

Sekarang setelah kita memahami perbedaan antara polimorfisme saat kompilasi dan saat runtime, mari kita pelajari lebih dalam fungsi virtual dan kata kunci override yang membuatnya lebih aman digunakan.

Saat kamu menandai fungsi sebagai virtual di base class, derived class dapat menyediakan implementasinya sendiri. Specifier override secara eksplisit memberi tahu compiler bahwa kamu bermaksud menimpa fungsi virtual:

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

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

Menggunakan override sangat penting karena dapat mendeteksi error saat kompilasi. Jika kamu tidak sengaja salah mengeja nama fungsi atau menggunakan parameter yang salah, compiler akan memberi tahu kamu alih-alih diam-diam membuat fungsi baru:

class Cat : public Animal {
public:
    void speek() override {  // Error compiler: tidak ada fungsi yang dapat ditimpa
        std::cout << "Meow!" << std::endl;
    }
};

Specifier final mencegah override lebih lanjut. Gunakan saat class turunan harus menjadi class terakhir yang meng-override fungsi tertentu:

class Bulldog : public Dog {
public:
    void speak() override final {
        std::cout << "Gruff woof!" << std::endl;
    }
};

class TinyBulldog : public Bulldog {
    void speak() override {}  // Error: tidak dapat menimpa fungsi final
};

Selalu gunakan override saat meng-override fungsi virtual. Ini mendokumentasikan maksudmu dan memungkinkan compiler memverifikasi bahwa kamu benar-benar meng-override fungsi virtual yang sudah ada.

challenge icon

Tantangan

Mudah

Mari kita buat sistem notifikasi yang menunjukkan kekuatan kata kunci override dan final dengan fungsi virtual. Kamu akan membuat hierarki penangan notifikasi. Beberapa method dapat disesuaikan lebih lanjut, sedangkan yang lain dikunci agar tidak dapat diubah.

Kamu akan mengatur kodemu dalam tiga file:

  • Notifier.h: Definisikan class dasar Notifier yang mewakili pengirim notifikasi apa pun:
    • Member std::string recipient yang dilindungi
    • Konstruktor yang menerima dan menyimpan nama penerima
    • Method virtual send(const std::string& message) yang mencetak: Notifying <recipient>: <message>
    • Method virtual getType() yang mengembalikan string "Generic"
    • Destruktor virtual
  • EmailNotifier.h: Definisikan class EmailNotifier yang mewarisi Notifier:
    • Member std::string domain yang privat
    • Konstruktor yang menerima penerima dan domain, lalu meneruskan penerima ke class dasar
    • Timpa send() agar mencetak: Emailing <recipient>@<domain>: <message>
    • Timpa getType() dan tandai dengan final. Method ini harus mengembalikan "Email"

    Lalu, definisikan class UrgentEmailNotifier yang mewarisi EmailNotifier:

    • Konstruktor yang menerima penerima dan domain, lalu meneruskan keduanya ke EmailNotifier
    • Timpa send() agar mencetak: [URGENT] Emailing <recipient>@<domain>: <message>
    • Catatan: Kamu tidak dapat menimpa getType() di sini karena method tersebut ditandai final di EmailNotifier
  • main.cpp: Baca tiga input, masing-masing pada baris terpisah:
    1. Nama penerima
    2. Domain email
    3. Teks pesan

    Buat tiga object notifier secara dinamis: Notifier dasar, EmailNotifier, dan UrgentEmailNotifier. Gunakan penerima yang sama untuk semuanya, dan domain yang sama jika diperlukan. Simpan semuanya dalam array berisi pointer Notifier*.

    Telusuri array tersebut dan untuk setiap notifier, cetak tipenya menggunakan getType(), lalu panggil send() dengan pesanmu. Format setiap entri seperti berikut:

    Type: <type>
    <send output>

    Cetak satu baris kosong di antara setiap notifier. Setelah selesai, bersihkan object yang dialokasikan secara dinamis.

Contohnya, dengan input Alice, company.com, dan Meeting at 3pm:

Type: Generic
Notifying Alice: Meeting at 3pm

Type: Email
Emailing Alice@company.com: Meeting at 3pm

Type: Email
[URGENT] Emailing Alice@company.com: Meeting at 3pm

Perhatikan bagaimana UrgentEmailNotifier dapat menimpa send() untuk menyesuaikan format pesan, tetapi mewarisi tipe "Email" dari EmailNotifier karena getType() ditandai final. Gunakan kata kunci override pada semua method yang ditimpa agar ketidakcocokan signature dapat diketahui saat compile.

Coba sendiri

#include <iostream>
#include <string>
#include "Notifier.h"
#include "EmailNotifier.h"

using namespace std;

int main() {
    // Baca input
    string recipient;
    string domain;
    string message;
    
    getline(cin, recipient);
    getline(cin, domain);
    getline(cin, message);
    
    // TODO: Buat array berisi 3 pointer Notifier*
    
    // TODO: Buat secara dinamis:
    // - Notifier dasar dengan recipient
    // - EmailNotifier dengan recipient dan domain
    // - UrgentEmailNotifier dengan recipient dan domain
    
    // TODO: Lakukan perulangan pada array dan, untuk setiap notifier:
    // - Cetak "Type: " diikuti hasil getType()
    // - Panggil send() dengan message
    // - Cetak baris kosong di antara notifier (jangan setelah yang terakhir)
    
    // TODO: Bersihkan object yang dialokasikan secara dinamis
    
    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