Yanıtlar:
Gönderen Wikipedia'nın Sanal fonksiyonu ...
Nesne yönelimli programlamada, C ++ ve Object Pascal gibi dillerde, sanal bir işlev veya sanal yöntem, dinamik dağıtmanın kolaylaştırıldığı devralınabilir ve geçersiz kılınabilen bir işlev veya yöntemdir. Bu kavram, nesne yönelimli programlamanın (OOP) (çalışma zamanı) polimorfizm bölümünün önemli bir parçasıdır. Kısacası, bir sanal işlev yürütülecek bir hedef işlevi tanımlar, ancak hedef derleme zamanında bilinmeyebilir.
Sanal olmayan bir işlevden farklı olarak, sanal bir işlev geçersiz kılındığında, en türetilmiş sürüm yalnızca oluşturulduğu düzeyden ziyade sınıf hiyerarşisinin tüm düzeylerinde kullanılır. Bu nedenle, temel sınıfın bir yöntemi sanal bir yöntemi çağırırsa , temel sınıfta tanımlanan sürüm yerine türetilmiş sınıfta tanımlanan sürüm kullanılır.
Bu, türetilmiş bir sınıfta hala geçersiz kılınabilen sanal olmayan işlevlerin tersidir, ancak "yeni" sürüm yalnızca türetilmiş sınıf ve aşağıda kullanılır, ancak temel sınıfın işlevselliğini hiç değiştirmez.
buna karşılık..
Saf sanal işlev veya saf sanal yöntem, türetilmiş sınıf soyut değilse türetilmiş bir sınıf tarafından uygulanması gereken sanal bir işlevdir.
Saf bir sanal yöntem mevcut olduğunda, sınıf "soyut" olur ve kendi başına başlatılamaz. Bunun yerine, saf sanal yöntemleri uygulayan türetilmiş bir sınıf kullanılmalıdır. Türetilmiş sınıfı bu yüzden saf sanal her taban sınıfı tanımlanmış olup gerekir tanımlamak veya bu türetilmiş bir sınıf, özet ve örneği alınamaz. Yalnızca soyut yöntemi olmayan bir sınıf somutlaştırılabilir.
Bir sanal, temel sınıfın işlevselliğini geçersiz kılmak için bir yol sağlar ve saf sanal bunu gerektirir .
pure
anahtar kelime eklemek istediğini söylediğine inanıyorum , ancak Bell Labs, C ++ 'ın büyük bir sürümünü yayınlamak üzereydi ve yöneticisi bu geç aşamada buna izin vermeyecekti. Anahtar kelime eklemek çok önemli.
Burada birkaç kişi tarafından tekrarlanan Wikipedia'nın sanal tanımına yorum yapmak istiyorum. [Bu cevap yazılırken] Wikipedia, sanal bir yöntemi alt sınıflarda geçersiz kılınabilecek bir yöntem olarak tanımladı. [Neyse ki, Wikipedia o zamandan beri düzenlenmiş ve şimdi bunu doğru bir şekilde açıklıyor.] Bu yanlış: sadece sanal olanları değil, herhangi bir yöntem alt sınıflarda geçersiz kılınabilir. Sanal olan size polimorfizm, yani çalışma zamanında bir yöntemin en türetilmiş geçersiz kılma seçimini yapma yeteneğidir .
Aşağıdaki kodu göz önünde bulundurun:
#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();
}
Bu programın çıktısı nedir?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Türetilmiş her Base yöntemini geçersiz kılar: sadece sanal olanı değil, aynı zamanda sanal olmayanı da.
Bir Base-pointer-to-Türved (bDerived) olduğunda, NonVirtual çağrıldığında Base sınıfı uygulamasını çağırır. Bu derleme zamanında çözümlenir: derleyici, bDerived bir Base * olduğunu görür, NonVirtual sanal değildir, bu nedenle sınıf Base çözünürlüğü yapar.
Ancak, Virtual çağrıldığında Derived sınıf uygulaması çağrılır. Sanal anahtar sözcüğü nedeniyle, yöntemin seçimi derleme zamanında değil , çalışma zamanında gerçekleşir. Derleme zamanında burada olan şey, derleyicinin bunun bir Base * olduğunu görmesi ve sanal bir yöntem çağırmasıdır, bu nedenle sınıf Base yerine vtable'a bir çağrı ekler. Bu vtable, çalışma zamanında somutlaştırılır, dolayısıyla en türetilmiş geçersiz kılma için çalışma zamanı çözünürlüğü.
Umarım bu çok kafa karıştırıcı değildir. Kısacası, herhangi bir yöntem geçersiz kılınabilir, ancak sadece sanal yöntemler size polimorfizm, yani en türetilen geçersiz kılmanın çalışma zamanı seçimini verir. Bununla birlikte, uygulamada, sanal olmayan bir yöntemin geçersiz kılınması kötü uygulama olarak kabul edilir ve nadiren kullanılır, bu yüzden birçok kişi (Wikipedia makalesini yazanlar dahil) sadece sanal yöntemlerin geçersiz kılınabileceğini düşünmektedir.
Derived*
Noktayı eve götürmek için aynı işlev çağrılarına sahip bir a eklemek yararlı olabilir . Aksi takdirde harika cevap
Sanal anahtar kelime C ++ 'a polimorfizmi destekleme yeteneği verir. Aşağıdaki gibi bir sınıfın nesnesine bir işaretçi olduğunda:
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();
}
Bu (aptal) örnekte, GetNumberOfLegs () işlevi, çağrıldığı nesnenin sınıfına göre uygun sayıyı döndürür.
Şimdi, 'SomeFunction' fonksiyonunu düşünün. Hayvandan türetildiği müddetçe, ona ne tür bir hayvan nesnesinin geçtiği umurunda değildir. Derleyici, temel sınıf olduğu için herhangi bir Hayvan türevi sınıfı bir Hayvana otomatik olarak atacaktır.
Bunu yaparsak:
Duck d;
SomeFunction(&d);
çıktı '2' olurdu. Bunu yaparsak:
Horse h;
SomeFunction(&h);
çıktı '4' olurdu. Bunu yapamayız:
Animal a;
SomeFunction(&a);
çünkü GetNumberOfLegs () sanal işlevi saf olduğu için derlenmeyecektir, yani sınıflar (alt sınıflar) türetilerek uygulanmalıdır.
Saf Sanal İşlevler çoğunlukla aşağıdakileri tanımlamak için kullanılır:
a) soyut sınıflar
Bunlar, onlardan türetmeniz ve daha sonra saf sanal işlevleri uygulamanız gereken temel sınıflardır.
b) arayüzler
Bunlar, tüm işlevlerin saf sanal olduğu ve böylece tüm işlevleri türetmeniz ve uygulamanız gereken 'boş' sınıflardır.
C ++ sınıfında sanal , bir yöntemin bir alt sınıfın üzerine yazılabileceğini (yani uygulayabileceğini) belirten anahtar kelimedir. Örneğin:
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;
};
Bu durumda, bir alt sınıf initShape işlevini bazı özel işler yapmak için geçersiz kılabilir :
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
Terimi sanal saf bir alt sınıf tarafından uygulanması gereken ve temel sınıf tarafından uygulanan edilmemiştir sanal fonksiyonları ifade eder. Sanal anahtar sözcüğü kullanarak ve yöntem bildiriminin sonuna = 0 ekleyerek bir yöntemi salt sanal olarak belirlersiniz .
Yani, Shape :: initShape'i saf sanal yapmak istiyorsanız aşağıdakileri yaparsınız:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
Sınıfınıza saf bir sanal yöntem ekleyerek, sınıfı , arabirimleri uygulamadan ayırmak için çok kullanışlı olan soyut bir temel sınıf haline getirirsiniz .
m_name
. Ne anlama m_
geliyor?
"Sanal", yöntemin alt sınıflarda geçersiz kılınabileceği, ancak temel sınıfta doğrudan çağrılabilir bir uygulamaya sahip olduğu anlamına gelir. "Saf sanal", doğrudan çağrılabilen bir uygulaması olmayan sanal bir yöntem olduğu anlamına gelir. Bu tür bir yöntem olmalıdır en az kalıtım hiyerarşisinde bir kez geçersiz - bir sınıf, uygulanmamış sanal yöntemleri varsa, inşa edilemez bu sınıfın nesneler ve derleme başarısız olur.
Saf sanal yöntemler üzerinden @quark noktaları olabilir bir uygulama var, ama saf sanal yöntemleri geçersiz kılınan olmalı gibi varsayılan uygulama doğrudan denilen edilemez. Varsayılan olarak saf-sanal bir yöntem örneği:
#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;
}
Yorumlara göre, derlemenin başarısız olup olmayacağı derleyiciye özgüdür. En azından GCC 4.3.3'te derlenmeyecektir:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Çıktı:
$ 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()
Sanal anahtar kelime nasıl çalışır?
İnsanın temel bir sınıf olduğunu, Hint'in insandan türediğini varsayın.
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Do_work () öğesini sanal olarak bildirmek şu anlama gelir: çağrılacak do_work () işlevi SADECE çalışma zamanında belirlenecektir.
Varsayalım,
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
Sanal kullanılmazsa, aynı nesne, hangi nesnenin çağırdığına bağlı olarak derleyici tarafından statik olarak belirlenir veya statik olarak bağlanır. Eğer bir Man nesnesi do_work () çağırırsa, Man's do_work (), BİR HİNTİN NESNESİNE ÇIKARILAR
En çok oy alan cevabın yanıltıcı olduğuna inanıyorum - Sanal olsun ya da olmasın herhangi bir yöntem türetilmiş sınıfta geçersiz kılınmış bir uygulamaya sahip olabilir. C ++ 'a özel atıfla, doğru fark çalışma zamanı (sanal kullanıldığında) bağlama ve derleme zamanıdır (sanal kullanılmaz, ancak bir yöntem geçersiz kılınır ve bir temel işaretçi türetilmiş bir nesneye işaret edilir) ilişkili işlevlerin bağlanmasıdır.
Başka bir yanıltıcı yorum var gibi görünüyor,
"Justin," saf sanal "yalnızca" bu işlev temel sınıf tarafından uygulanamaz "anlamına gelen bir terimdir (bir anahtar kelime değil, aşağıdaki cevabıma bakın).
BU YANLIŞ! Tamamen sanal işlevlerin de bir bedeni olabilir ve UYGULANABİLİR! Gerçek şu ki, soyut bir sınıfın saf sanal işlevi statik olarak çağrılabilir! Çok iyi iki yazar Bjarne Stroustrup ve Stan Lippman ... çünkü dili yazdılar.
Sanal işlev, temel sınıfta bildirilen ve türetilmiş sınıf tarafından yeniden tanımlanan bir üye işlevdir. Sanal işlev miras sırasına göre hiyerarşiktir. Türetilmiş bir sınıf sanal bir işlevi geçersiz kılmadığında, temel sınıfında tanımlanan işlev kullanılır.
Saf sanal işlev, temel sınıfa göre tanım içermeyen bir işlevdir. Temel sınıfta bir uygulaması yoktur. Türetilmiş herhangi bir sınıf bu işlevi geçersiz kılmalıdır.
Varsayılan olarak statik yöntem bağlaması kullanan Simula, C ++ ve C #, programcı sanal olarak etiketleyerek belirli yöntemlerin dinamik bağlamayı kullanması gerektiğini belirtebilir. Dinamik yöntem bağlama, nesne yönelimli programlamanın merkezinde yer alır.
Nesneye yönelik programlama üç temel kavram gerektirir: kapsülleme, kalıtım ve dinamik yöntem bağlama.
Kapsülleme , bir soyutlamanın uygulama ayrıntılarının basit bir arayüzün arkasında gizlenmesini sağlar.
Kalıtım , yeni bir soyutlamanın, özelliklerinin bir kısmını veya tamamını otomatik olarak elde ederek mevcut bir soyutlamanın bir uzantısı veya iyileştirmesi olarak tanımlanmasını sağlar.
Dinamik yöntem bağlaması , yeni soyutlamanın, eski soyutlamayı bekleyen bir bağlamda kullanıldığında bile yeni davranışını görüntülemesini sağlar.
Sanal yöntemler sınıf türetilerek geçersiz kılınabilir, ancak temel sınıfta (geçersiz kılınacak olan) bir uygulamaya ihtiyaç duyar
Saf sanal yöntemlerin temel sınıf uygulaması yoktur. Türetilmiş sınıflar tarafından tanımlanmaları gerekir. (Teknik olarak geçersiz kılınan doğru terim değildir, çünkü geçersiz kılınacak bir şey yoktur).
Türetilmiş sınıf temel sınıfın bir yöntemini geçersiz kıldığında, sanal varsayılan java davranışına karşılık gelir.
Saf Sanal yöntemler soyut yöntemlerin soyut sınıflardaki davranışlarına karşılık gelir. Ve sadece saf sanal yöntemler ve sabitler içeren bir sınıf bir Arabirim için cpp-kolye olacaktır.
Saf Sanal İşlev
bu kodu dene
#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();
}
Sınıfta anotherClass sayHellow işlevini kaldırın ve kodu çalıştırın. Bir sınıf saf bir sanal işlev içerdiğinde, o sınıftan hiçbir nesne oluşturulamaz ve bu devralındıktan sonra türetilmiş sınıfı bu işlevi uygulamalıdır.
Sanal işlev
başka bir kod dene
#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!
}
Burada sayHellow işlevi temel sınıfta sanal olarak işaretlenir.Değişken sınıfta işlevi aramayı deneyen ve işlevi uygulayan derleyici der. Bulunamazsa temel olanı yürütün.
"Sanal işlev veya sanal yöntem, aynı imzaya sahip bir işlev tarafından devralınan bir sınıf içinde davranışı geçersiz kılınabilen bir işlev veya yöntemdir" - wikipedia
Bu sanal işlevler için iyi bir açıklama değildir. Çünkü bir üye sanal olmasa bile, sınıfların miras alınması onu geçersiz kılabilir. Kendiniz deneyebilirsiniz.
Bir fonksiyon parametre olarak bir temel sınıf aldığında fark kendini gösterir. Girdi olarak devralma sınıfı verdiğinizde, bu işlev geçersiz kılma işlevinin temel sınıf uygulamasını kullanır. Ancak, bu işlev sanal ise, türetme sınıfında uygulanan işlevi kullanır.
Sanal işlevlerin temel sınıfta ve ayrıca türetilmiş sınıfta bir tanımı olması gerekir, ancak gerekli değildir; örneğin, ToString () veya toString () işlevi Sanaldır, böylece kullanıcı tanımlı sınıf (lar) da geçersiz kılarak kendi uygulamanızı sağlayabilirsiniz.
Sanal işlevler normal sınıfta bildirilir ve tanımlanır.
Saf sanal işlev "= 0" ile biten bildirilmelidir ve yalnızca soyut sınıfta bildirilebilir.
Saf sanal işlev (ler) e sahip soyut bir sınıf, o saf sanal işlevlerin tanımına / tanımlarına sahip olamaz, bu nedenle uygulamanın o soyut sınıftan türetilen sınıf (lar) da sağlanması gerektiğini ima eder.