Jawaban:
Dari fungsi Virtual Wikipedia ...
Dalam pemrograman berorientasi objek, dalam bahasa seperti C ++, dan Object Pascal, fungsi virtual atau metode virtual adalah fungsi atau metode yang dapat diwariskan dan dapat ditimpa untuk pengiriman dinamis yang difasilitasi. Konsep ini merupakan bagian penting dari bagian (runtime) polimorfisme pemrograman berorientasi objek (OOP). Singkatnya, fungsi virtual mendefinisikan fungsi target untuk dieksekusi, tetapi target mungkin tidak diketahui pada waktu kompilasi.
Tidak seperti fungsi non-virtual, ketika fungsi virtual ditimpa, versi yang paling diturunkan digunakan di semua tingkatan hirarki kelas, bukan hanya pada tingkat di mana ia dibuat. Oleh karena itu jika satu metode kelas dasar memanggil metode virtual, versi yang ditentukan dalam kelas turunan akan digunakan sebagai pengganti versi yang didefinisikan dalam kelas dasar.
Ini berbeda dengan fungsi non-virtual, yang masih dapat ditimpa dalam kelas turunan, tetapi versi "baru" hanya akan digunakan oleh kelas turunan dan di bawahnya, tetapi tidak akan mengubah fungsi dari kelas dasar sama sekali.
sedangkan..
Fungsi virtual murni atau metode virtual murni adalah fungsi virtual yang harus diterapkan oleh kelas turunan jika kelas turunannya tidak abstrak.
Ketika metode virtual murni ada, kelasnya "abstrak" dan tidak bisa dipakai sendiri. Sebagai gantinya, kelas turunan yang mengimplementasikan metode virtual-virtual harus digunakan. Pure-virtual sama sekali tidak didefinisikan di kelas dasar, jadi kelas turunan harus mendefinisikannya, atau kelas turunannya juga abstrak, dan tidak dapat dipakai. Hanya kelas yang tidak memiliki metode abstrak yang dapat dipakai.
Virtual menyediakan cara untuk mengesampingkan fungsionalitas kelas dasar, dan virtual-murni membutuhkannya .
pure
kata kunci, tetapi Bell Labs akan membuat rilis besar C ++, dan manajernya tidak mengizinkannya pada tahap akhir itu. Menambahkan kata kunci adalah masalah besar.
Saya ingin mengomentari definisi Wikipedia tentang virtual, seperti yang diulang oleh beberapa di sini. [Pada saat jawaban ini ditulis,] Wikipedia mendefinisikan metode virtual sebagai salah satu yang dapat ditimpa dalam subkelas. [Untungnya, Wikipedia telah diedit sejak itu, dan sekarang menjelaskan hal ini dengan benar.] Itu tidak benar: metode apa pun, tidak hanya yang virtual, dapat ditimpa dalam subkelas. Apa yang dilakukan virtual adalah memberi Anda polimorfisme, yaitu, kemampuan untuk memilih saat run-override metode yang paling diturunkan .
Pertimbangkan kode berikut:
#include <iostream>
using namespace std;
class Base {
public:
void NonVirtual() {
cout << "Base NonVirtual called.\n";
}
virtual void Virtual() {
cout << "Base Virtual called.\n";
}
};
class Derived : public Base {
public:
void NonVirtual() {
cout << "Derived NonVirtual called.\n";
}
void Virtual() {
cout << "Derived Virtual called.\n";
}
};
int main() {
Base* bBase = new Base();
Base* bDerived = new Derived();
bBase->NonVirtual();
bBase->Virtual();
bDerived->NonVirtual();
bDerived->Virtual();
}
Apa output dari program ini?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Berasal menimpa setiap metode Base: tidak hanya yang virtual, tetapi juga non-virtual.
Kami melihat bahwa ketika Anda memiliki Base-pointer-to-Derived (bDerived), memanggil panggilan NonVirtual implementasi kelas Base. Ini diselesaikan pada waktu kompilasi: kompilator melihat bahwa bDerived adalah Basis *, bahwa NonVirtual bukan virtual, sehingga ia melakukan resolusi pada basis kelas.
Namun, memanggil panggilan Virtual implementasi kelas turunan. Karena kata kunci virtual, pemilihan metode terjadi pada saat run-time , bukan waktu kompilasi. Apa yang terjadi di sini pada waktu kompilasi adalah bahwa kompiler melihat bahwa ini adalah Basis *, dan itu memanggil metode virtual, sehingga memasukkan panggilan ke vtable, bukan Basis kelas. Vtable ini dipakai pada saat run-time, maka resolusi run-time ke override yang paling diturunkan.
Saya harap ini tidak terlalu membingungkan. Singkatnya, metode apa pun dapat diganti, tetapi hanya metode virtual yang memberi Anda polimorfisme, yaitu pemilihan run-time dari penggantian yang paling diturunkan. Namun dalam praktiknya, mengganti metode non-virtual dianggap praktik buruk dan jarang digunakan, sehingga banyak orang (termasuk siapa pun yang menulis artikel Wikipedia) berpikir bahwa hanya metode virtual yang dapat ditimpa.
Derived*
dengan panggilan fungsi yang sama untuk mengarahkan titik pulang. Jika tidak, jawaban yang bagus
Kata kunci virtual memberi C ++ kemampuannya untuk mendukung polimorfisme. Ketika Anda memiliki pointer ke objek dari beberapa kelas seperti:
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
Dalam contoh (konyol) ini, fungsi GetNumberOfLegs () mengembalikan angka yang sesuai berdasarkan kelas objek yang dipanggil.
Sekarang, pertimbangkan fungsi 'SomeFunction'. Tidak peduli apa jenis objek hewan yang diteruskan padanya, asalkan itu berasal dari Hewan. Compiler akan secara otomatis mengirimkan kelas turunan Animal ke Animal karena kelas dasar.
Jika kita melakukan ini:
Duck d;
SomeFunction(&d);
itu akan menghasilkan '2'. Jika kita melakukan ini:
Horse h;
SomeFunction(&h);
itu akan menghasilkan '4'. Kami tidak bisa melakukan ini:
Animal a;
SomeFunction(&a);
karena itu tidak akan dikompilasi karena fungsi virtual GetNumberOfLegs () menjadi murni, yang berarti harus diimplementasikan dengan menurunkan kelas (subclass).
Fungsi Virtual Murni sebagian besar digunakan untuk mendefinisikan:
a) kelas abstrak
Ini adalah kelas dasar di mana Anda harus mengambil darinya dan kemudian mengimplementasikan fungsi virtual murni.
b) antarmuka
Ini adalah kelas 'kosong' di mana semua fungsi adalah virtual murni dan karenanya Anda harus menurunkan dan kemudian mengimplementasikan semua fungsi.
Dalam kelas C ++, virtual adalah kata kunci yang menunjukkan bahwa, suatu metode dapat diganti (yaitu diimplementasikan oleh) sebuah subkelas. Sebagai contoh:
class Shape
{
public:
Shape();
virtual ~Shape();
std::string getName() // not overridable
{
return m_name;
}
void setName( const std::string& name ) // not overridable
{
m_name = name;
}
protected:
virtual void initShape() // overridable
{
setName("Generic Shape");
}
private:
std::string m_name;
};
Dalam hal ini, subclass dapat mengesampingkan fungsi initShape untuk melakukan beberapa pekerjaan khusus:
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
Istilah virtual murni mengacu pada fungsi virtual yang perlu diimplementasikan oleh subclass dan belum diimplementasikan oleh kelas dasar. Anda menetapkan metode sebagai virtual murni dengan menggunakan kata kunci virtual dan menambahkan a = 0 pada akhir deklarasi metode.
Jadi, jika Anda ingin membuat Shape :: initShape pure virtual Anda akan melakukan hal berikut:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
Dengan menambahkan metode virtual murni ke kelas Anda, Anda membuat kelas menjadi kelas dasar abstrak yang sangat berguna untuk memisahkan antarmuka dari implementasi.
m_name
. Apa m_
artinya?
"Virtual" berarti bahwa metode tersebut dapat ditimpa dalam subkelas, tetapi memiliki implementasi yang dapat dipanggil langsung di kelas dasar. "Pure virtual" berarti ini adalah metode virtual tanpa implementasi yang dapat dipanggil langsung. Metode seperti itu harus ditimpa setidaknya satu kali dalam hierarki warisan - jika suatu kelas memiliki metode virtual yang tidak diterapkan, objek dari kelas itu tidak dapat dibangun dan kompilasi akan gagal.
@quark menunjukkan bahwa metode virtual murni dapat memiliki implementasi, tetapi karena metode virtual murni harus ditimpa, implementasi default tidak dapat dipanggil secara langsung. Berikut adalah contoh metode virtual murni dengan default:
#include <cstdio>
class A {
public:
virtual void Hello() = 0;
};
void A::Hello() {
printf("A::Hello\n");
}
class B : public A {
public:
void Hello() {
printf("B::Hello\n");
A::Hello();
}
};
int main() {
/* Prints:
B::Hello
A::Hello
*/
B b;
b.Hello();
return 0;
}
Menurut komentar, apakah kompilasi akan gagal atau tidak adalah khusus kompiler. Setidaknya dalam GCC 4.3.3, itu tidak akan dikompilasi:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Keluaran:
$ g++ -c virt.cpp
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note: because the following virtual functions are pure within ‘A’:
virt.cpp:3: note: virtual void A::Hello()
Bagaimana cara kerja kata kunci virtual?
Asumsikan bahwa Manusia adalah kelas dasar, India berasal dari manusia.
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Mendeklarasikan do_work () sebagai virtual berarti: do_work () yang akan dipanggil HANYA ditentukan pada saat run-time.
Misalkan saya lakukan,
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
Jika virtual tidak digunakan, hal yang sama ditentukan secara statis atau terikat secara statis oleh kompiler, tergantung pada objek yang dipanggil. Jadi, jika sebuah objek dari Man memanggil do_work (), do_work () Man disebut EVEN THOUGH POINTS TO OBJECT INDIAN
Saya percaya bahwa jawaban yang dipilih adalah menyesatkan - Setiap metode apakah virtual dapat memiliki implementasi yang ditimpa di kelas turunan. Dengan referensi spesifik ke C ++ perbedaan yang benar adalah run-time (ketika virtual digunakan) mengikat dan mengkompilasi-waktu (ketika virtual tidak digunakan tetapi metode ditimpa dan penunjuk basis diarahkan ke objek yang diturunkan) mengikat fungsi terkait.
Tampaknya ada komentar menyesatkan lainnya yang mengatakan,
"Justin, 'virtual murni' hanyalah sebuah istilah (bukan kata kunci, lihat jawaban saya di bawah) yang dulu berarti" fungsi ini tidak dapat diimplementasikan oleh kelas dasar. "
INI SALAH! Fungsi virtual murni juga dapat memiliki tubuh DAN DAPAT DITERAPKAN! Yang benar adalah bahwa fungsi virtual murni kelas abstrak dapat disebut secara statis! Dua penulis yang sangat baik adalah Bjarne Stroustrup dan Stan Lippman .... karena mereka menulis bahasa.
Fungsi virtual adalah fungsi anggota yang dideklarasikan dalam kelas dasar dan yang didefinisikan ulang oleh kelas turunan. Fungsi virtual bersifat hierarkis sesuai urutan warisan. Ketika kelas turunan tidak mengesampingkan fungsi virtual, fungsi yang didefinisikan dalam kelas dasarnya digunakan.
Fungsi virtual murni adalah yang tidak mengandung definisi relatif terhadap kelas dasar. Tidak memiliki implementasi di kelas dasar. Setiap kelas turunan harus menimpa fungsi ini.
Simula, C ++, dan C #, yang menggunakan pengikatan metode statis secara default, pemrogram dapat menentukan bahwa metode tertentu harus menggunakan pengikatan dinamis dengan memberi labelnya sebagai virtual. Pengikatan metode dinamis adalah pusat pemrograman berorientasi objek.
Pemrograman berorientasi objek membutuhkan tiga konsep dasar: enkapsulasi, pewarisan, dan pengikatan metode dinamis.
Enkapsulasi memungkinkan detail implementasi abstraksi disembunyikan di balik antarmuka yang sederhana.
Warisan memungkinkan abstraksi baru untuk didefinisikan sebagai perpanjangan atau penyempurnaan dari beberapa abstraksi yang ada, memperoleh beberapa atau semua karakteristiknya secara otomatis.
Pengikatan metode dinamis memungkinkan abstraksi baru untuk menampilkan perilaku barunya bahkan ketika digunakan dalam konteks yang mengharapkan abstraksi lama.
Metode virtual DAPAT ditimpa oleh menurunkan kelas, tetapi membutuhkan implementasi di kelas dasar (yang akan ditimpa)
Metode virtual murni tidak memiliki implementasi kelas dasar. Mereka perlu didefinisikan oleh kelas turunan. (Jadi secara teknis diganti bukan istilah yang tepat, karena tidak ada yang menimpanya).
Virtual berhubungan dengan perilaku java default, ketika kelas turunan menimpa metode kelas dasar.
Metode Virtual murni sesuai dengan perilaku metode abstrak dalam kelas abstrak. Dan kelas yang hanya berisi metode virtual murni dan konstanta akan menjadi cpp-pendant ke sebuah Interface.
Fungsi Virtual Murni
coba kode ini
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()=0;
};
class anotherClass:aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"hellow World";
}
};
int main()
{
//aClassWithPureVirtualFunction virtualObject;
/*
This not possible to create object of a class that contain pure virtual function
*/
anotherClass object;
object.sayHellow();
}
Di kelas anotherClass menghapus fungsi sayHellow dan menjalankan kode. Anda akan mendapatkan kesalahan! Karena ketika sebuah kelas berisi fungsi virtual murni, tidak ada objek yang dapat dibuat dari kelas itu dan itu diwarisi maka kelas turunannya harus mengimplementasikan fungsi itu.
Fungsi virtual
coba kode lain
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()
{
cout<<"from base\n";
}
};
class anotherClass:public aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"from derived \n";
}
};
int main()
{
aClassWithPureVirtualFunction *baseObject=new aClassWithPureVirtualFunction;
baseObject->sayHellow();///call base one
baseObject=new anotherClass;
baseObject->sayHellow();////call the derived one!
}
Di sini fungsi sayHellow ditandai sebagai virtual di kelas dasar. Dikatakan kompiler yang mencoba mencari fungsi di kelas turunan dan mengimplementasikan fungsinya. Jika tidak ditemukan maka jalankan basisnya. Terima kasih
"Fungsi virtual atau metode virtual adalah fungsi atau metode yang perilakunya dapat ditimpa dalam kelas pewarisan oleh fungsi dengan tanda tangan yang sama" - wikipedia
Ini bukan penjelasan yang bagus untuk fungsi virtual. Karena, bahkan jika anggota bukan virtual, mewarisi kelas dapat menimpanya. Anda dapat mencoba dan melihatnya sendiri.
Perbedaannya menunjukkan dirinya sendiri ketika suatu fungsi mengambil kelas dasar sebagai parameter. Saat Anda memberikan kelas pewarisan sebagai input, fungsi itu menggunakan implementasi kelas dasar dari fungsi overriden. Namun, jika fungsi itu virtual, ia menggunakan salah satu yang diimplementasikan dalam kelas turunan.
Fungsi virtual harus memiliki definisi dalam kelas dasar dan juga dalam kelas turunan tetapi tidak perlu, misalnya fungsi ToString () atau toString () adalah Virtual sehingga Anda dapat menyediakan implementasi Anda sendiri dengan menimpanya di kelas yang ditentukan pengguna.
Fungsi virtual dideklarasikan dan didefinisikan dalam kelas normal.
Fungsi virtual murni harus dideklarasikan diakhiri dengan "= 0" dan itu hanya dapat dideklarasikan dalam kelas abstrak.
Kelas abstrak yang memiliki fungsi virtual murni tidak dapat memiliki definisi fungsi virtual murni itu, sehingga ini menyiratkan bahwa implementasi harus disediakan di kelas yang berasal dari kelas abstrak itu.