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.
Tantangan
MudahMari 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 dasarNotifieryang mewakili pengirim notifikasi apa pun:- Member
std::string recipientyang 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
- Member
EmailNotifier.h: Definisikan classEmailNotifieryang mewarisiNotifier:- Member
std::string domainyang 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 denganfinal. Method ini harus mengembalikan"Email"
Lalu, definisikan class
UrgentEmailNotifieryang mewarisiEmailNotifier:- 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 ditandaifinaldiEmailNotifier
- Member
main.cpp: Baca tiga input, masing-masing pada baris terpisah:- Nama penerima
- Domain email
- Teks pesan
Buat tiga object notifier secara dinamis:
Notifierdasar,EmailNotifier, danUrgentEmailNotifier. Gunakan penerima yang sama untuk semuanya, dan domain yang sama jika diperlukan. Simpan semuanya dalam array berisi pointerNotifier*.Telusuri array tersebut dan untuk setiap notifier, cetak tipenya menggunakan
getType(), lalu panggilsend()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 3pmPerhatikan 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;
}
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