it-swarm.dev

panggilan fungsi virtual dari kelas dasar

Katakanlah kita memiliki:


Class Base
{   
    virtual void f(){g();};
    virtual void g(){//Do some Base related code;}
};

Class Derived : public Base
{   
    virtual void f(){Base::f();};
    virtual void g(){//Do some Derived related code};
};

int main()
{
    Base *pBase = new Derived;
    pBase->f();
    return 0;  
}

g() mana yang akan dipanggil dari Base::f()? Base::g() atau Derived::g()?

Terima kasih... 

45
Gal Goldman

G dari kelas turunan akan dipanggil. Jika Anda ingin memanggil fungsi di pangkalan, panggil

Base::g();

sebagai gantinya. Jika Anda ingin memanggil turunan, tetapi masih ingin membuat versi dasar dipanggil, atur agar versi turunan dari g memanggil versi dasar dalam pernyataan pertama:

virtual void g() {
    Base::g();
    // some work related to derived
}

Fakta bahwa fungsi dari basis dapat memanggil metode virtual dan kontrol ditransfer ke kelas turunan digunakan dalam pola desain metode templat. Untuk C++, itu lebih dikenal sebagai Non-Virtual-Interface . Ini banyak digunakan juga di pustaka standar C++ (buffer aliran C++ misalnya memiliki fungsi pub... yang memanggil fungsi virtual yang melakukan pekerjaan nyata. Misalnya pubseekoff panggilan dilindungi seekoff). Saya menulis contoh dalam jawaban ini: Bagaimana Anda memvalidasi keadaan internal objek?

51

Ini adalah Derived :: g, kecuali jika Anda memanggil g dalam konstruktor Base. Karena konstruktor Basis dipanggil sebelum objek Derived dibangun, Derived :: g tidak bisa secara logis disebut karena ia dapat memanipulasi variabel yang belum dibangun, jadi Base :: g akan dipanggil.

6
Syed Lavasani

pBase adalah sebuah pointer ke sebuah basis . pBase = new Derived mengembalikan sebuah pointer ke Derived - Derived is-a Base.

Jadi pBase = turunan baru itu valid.

pBase mereferensikan sebuah Base, jadi ia akan melihat Derived seolah-olah itu adalah Base.

pBase-> f () akan memanggil Derive :: f ();

Kemudian kita lihat dalam kode itu:

Turunkan :: f () -> Base :: f () -> g() - tetapi g mana ??

Yah, ia memanggil Derive :: g () karena itu adalah g yang pBase "arahkan" ke.

Jawaban: Turunkan :: g ()

5
Jacob

Yah ... Saya tidak yakin ini harus dikompilasi. Pengikut,

Base *pBase = new Derived;

tidak valid kecuali jika Anda memiliki:

Class Derived : public Base

Apakah itu yang Anda maksudkan? Jika ini yang Anda maksud, 

pBase->f();

Maka tumpukan panggilan akan seperti ini:

Derived::f()
    Base::f()
        Derived::g()
2
user48956

Sebenarnya menjalankan kode Anda menunjukkan bahwa Derived :: g () dipanggil.

1
KJAWolf

Seperti yang Anda tetapkan g() sebagai virtual, g() yang paling diturunkan akan dilihat dalam tabel kelas dan dipanggil terlepas dari jenis kode yang saat ini diakses oleh Anda. 

Lihat C++ FAQ pada fungsi virtual .

1
Thorsten79

Metode kelas turunan akan dipanggil.

Ini karena penyertaan vtables dalam kelas yang memiliki fungsi virtual dan kelas yang mengesampingkan fungsi tersebut. (Ini juga dikenal sebagai pengiriman dinamis.) Inilah yang sebenarnya terjadi: vtable dibuat untuk Base dan vtable dibuat untuk Derived, karena hanya ada satu vtable per kelas. Karena pBase memanggil fungsi yang virtual dan overrode, sebuah penunjuk ke vtable untuk Derived disebut. Sebut saja d_ptr, juga dikenal sebagai vpointer:

int main()
{
    Base *pBase = new Derived;
    pBase->d_ptr->f();
    return 0;  
}

Sekarang d_ptr memanggil Derived::f(), yang memanggil Base::f(), yang kemudian melihat vtable untuk melihat g() apa yang digunakan. Karena vpointer hanya tahu g() dalam Derived, itulah yang kami gunakan. Oleh karena itu, Derived::g() dipanggil.

0
Jossie Calderon

Saya pikir Anda mencoba menciptakan Pola Metode Templat

0
Lazin