Apakah SEMUA fungsi virtual perlu diimplementasikan di kelas turunan?

91

Ini mungkin tampak seperti pertanyaan sederhana, tetapi saya tidak dapat menemukan jawabannya di tempat lain.

Misalkan saya memiliki yang berikut:

class Abstract {
public:
    virtual void foo() = 0;
    virtual void bar();
}

class Derived : Abstract {
public:
    virtual void foo();
}

Apakah ok class Derived tidak mengimplementasikan fungsi bar ()? Bagaimana jika tidak SEMUA kelas turunan saya membutuhkan fungsi bar (), tetapi beberapa membutuhkan. Apakah semua fungsi virtual dari kelas dasar abstrak perlu diimplementasikan di kelas turunan, atau hanya yang virtual murni? Terima kasih

mikestaub.dll
sumber

Jawaban:

82

Kelas turunan tidak harus mengimplementasikan sendiri semua fungsi virtual. Mereka hanya perlu menerapkan yang murni . 1 Artinya Derivedkelas dalam soal tersebut benar. Ini mewarisi para barimplementasi dari kelas leluhurnya, Abstract. (Ini mengasumsikan bahwa Abstract::barditerapkan di suatu tempat. Kode dalam pertanyaan mendeklarasikan metode, tetapi tidak mendefinisikannya. Anda dapat mendefinisikannya sebaris seperti yang ditunjukkan jawaban Trenki , atau Anda dapat mendefinisikannya secara terpisah.)


1 Dan bahkan kemudian, hanya jika kelas turunan akan dipakai . Jika kelas turunan tidak dipakai secara langsung, tetapi hanya ada sebagai basis kelas dari kelas yang lebih diturunkan, maka itu mereka kelas yang bertanggung jawab untuk memiliki semua metode virtual murni mereka dilaksanakan. Kelas "menengah" dalam hierarki diizinkan untuk membiarkan beberapa metode virtual murni tidak diimplementasikan, seperti kelas dasar. Jika kelas "menengah" tidak menerapkan metode virtual murni, maka keturunannya akan mewarisi implementasi itu, sehingga mereka tidak perlu kembali melaksanakan sendiri.

Rob Kennedy
sumber
3
Dan bahkan ini (implementasi fungsi virtual murni) hanya jika mereka dimaksudkan untuk digunakan (berbeda dengan kelas dasar abstrak itu sendiri).
Christian Rau
1
Itulah yang saya pikirkan. Tetapi saya melakukan ini dalam proyek saya, dan saya mendapatkan kesalahan penautan yang mengatakan bahwa ada "simbol eksternal yang belum terselesaikan" untuk Derived :: bar (); Tapi saya tidak pernah mendeklarasikan bar dalam Derived, jadi mengapa linker mencari function body?
mikestaub
1
@pixelpusher Tentu saja Derived::barpunya fungsi body, yaitu Abstract::bar. Jadi tampaknya unit terjemahan di mana itu didefinisikan (apakah itu bahkan ditentukan di mana saja?) Tidak ditautkan ke unit terjemahan tempat ia dipanggil.
Christian Rau
2
@ Rob: They only need to implement the pure ones.Ini menyesatkan. Kelas turunan juga tidak perlu mengimplementasikan fungsi virtual murni .
Nawaz
Saya menghargai bantuan tetapi @trenki tepat sasaran. Meskipun Anda juga benar Christian Rau, karena TIDAK didefinisikan.
mikestaub
47

Hanya metode virtual murni yang harus diimplementasikan di kelas turunan, tetapi Anda masih memerlukan definisi (dan bukan hanya deklarasi) dari metode virtual lainnya. Jika Anda tidak memberikannya, linker mungkin akan mengeluh.

Jadi, hanya menempatkan {}setelah metode virtual opsional Anda memberi Anda implementasi default kosong:

class Abstract {
public:
    virtual void foo() = 0; // pure virtual must be overridden
    virtual void bar() {}   // virtual with empty default implementation
};

class Derived : Abstract {
public:
    virtual void foo();
};

Implementasi default yang lebih terlibat akan masuk ke file sumber terpisah.

trenki
sumber
7

Standar ISO C ++ menetapkan bahwa semua metode virtual kelas yang bukan virtual murni harus ditentukan.

Sederhananya, aturannya adalah:
Jika kelas turunan Anda menimpa metode virtual kelas Basis maka ia harus memberikan definisi juga. Jika tidak, kelas Basis harus memberikan definisi metode itu.

Sesuai aturan di atas dalam contoh kode Anda, virtual void bar();membutuhkan definisi di kelas Base.

Referensi:

C ++ 03 Standar: 10.3 Fungsi virtual [class.virtual]

Fungsi virtual yang dideklarasikan dalam kelas harus didefinisikan, atau dideklarasikan murni (10.4) di kelas itu, atau keduanya; tetapi tidak diperlukan diagnosis (3.2).

Jadi Anda harus membuat fungsi virtual murni atau memberikan definisi untuk itu.

The gcc faq doccuments itu juga:

Standar ISO C ++ menetapkan bahwa semua metode virtual kelas yang bukan virtual murni harus ditentukan, tetapi tidak memerlukan diagnostik apa pun untuk pelanggaran aturan ini [class.virtual]/8. Berdasarkan asumsi ini, GCC hanya akan memancarkan konstruktor yang didefinisikan secara implisit, operator penugasan, destruktor, dan tabel virtual kelas di unit terjemahan yang mendefinisikan metode non-inline pertamanya.

Oleh karena itu, jika Anda gagal untuk mendefinisikan metode khusus ini, penaut mungkin mengeluh tentang kurangnya definisi untuk simbol yang tampaknya tidak terkait. Sayangnya, untuk memperbaiki pesan kesalahan ini, mungkin perlu mengubah linker, dan ini tidak selalu bisa dilakukan.

Solusinya adalah memastikan bahwa semua metode virtual yang tidak murni ditentukan. Perhatikan bahwa destruktor harus ditentukan meskipun ia dideklarasikan sebagai virtual-murni [class.dtor]/7.

Alok Save
sumber
3

Ya, tidak apa-apa ... Anda hanya perlu mengimplementasikan fungsi virtual murni apa pun untuk membuat instance kelas yang diturunkan dari kelas dasar abstrak.

Jason
sumber
1

Ya, Benar bahwa kelas Turunan harus MENGATASI fungsi yang Virtual Murni di Kelas Induk. Kelas induk yang memiliki Fungsi Virtual Murni disebut Kelas Abstrak hanya karena kelas Anak itu harus memberikan Fungsi Virtual Murni pada tubuhnya sendiri.

Untuk Fungsi Virtual Normal: - Tidak perlu menimpanya lebih lanjut, karena beberapa kelas anak mungkin memiliki fungsi itu, beberapa mungkin tidak.

Tujuan utama dari mekanisme Virtual Function adalah Run Time Polymorphism, apakah tujuan utama dari Pure Virtual Function (Kelas Abstrak) adalah untuk mewajibkan memiliki nama Fungsi yang sama dengan tubuhnya.

CodeCodeCode
sumber