2009-09-10 26 views
20

Ben foo sınıfında D bildirilen, ancak sanal işaretli değilse, o zaman aşağıdaki kodu (bakılmaksızın d dinamik türden) D içinde foo uygulanmasını çağırır beklenebilir. Ancak, aşağıdaki programda, durum böyle değildir. Ancak, aşağıdaki programda bu durum söz konusu değildir. Bunu açıklayan var mı? Sanal bir işlevi geçersiz kılarsa, bir yöntem otomatik olarak sanal mıdır?C++, sanal bir işlevi geçersiz kılarsa, otomatik olarak sanal bir işlev midir?

E 
+4

static_cast gereksiz - 'D & D = * static_cast (&e);' D & d = e 'eşdeğerdir;' nedeniyle Ge * E */E örtülü döküm için/D &. –

+0

C++ 11 işlev bildirimi için "geçersiz kılma" ekleyerek, temel sınıf işlevini geçersiz kılma niyetinizi netleştirir. Ayrıca, bildirdiğiniz işlevin, temelden gelen sabitlikten farklı olması durumunda, derleyiciden bir hata tetikler. Örneğin std :: exception'dan türetip, what() non-const) – Ghita

cevap

22

Standart 10.3.2 (class.virtual) der:

sanal elemanı işlevi VF Base, bir üye işlevi vf doğrudan veya dolaylı olarak elde edilen, bir sınıf temel ve türetilmiş bir sınıfta bildirilen edilirse Aynı adı ve Base :: vf olarak aynı parametre listesiyle birlikte, daha sonra Türetilmiş :: vf de sanaltır (ister bildirilmiş olsun ya da olmasın) ve geçersiz kılar *

[Footnote: Aynı ada sahip bir işlev Ancak sanal bir işlev olarak farklı bir parametre listesi (yan tümcesi) zorunlu olarak sanal değildir ve geçersiz kılmaz. Sanal belirticinin bir geçersiz kılma işlevinin beyanında kullanımı yasaldır ancak gereksizdir (boş anlambilimine sahiptir). Geçersiz kılmayı belirlemede erişim denetimi (yan tümce sınıfı. Access) dikkate alınmaz. --- uç foonote]

17

Hızlı cevap hayır olabilir, ama doğru cevap öylesine ağır basan, evet

C++ işlevi gizleme bilmediği geçerli:

#include <iostream> 

using namespace std; 

class C { 
public: 
     virtual void foo() { cout << "C" << endl; } 
}; 

class D : public C { 
public: 
     void foo() { cout << "D" << endl; } 
}; 

class E : public D { 
public: 
     void foo() { cout << "E" << endl; } 
}; 

int main(int argc, char **argv) 
{ 
     E& e = *new E; 
     D& d = *static_cast<D*>(&e); 
     d.foo(); 
     return 0; 
} 

yukarıdaki Programın çıktısı Sanal işlevi olmayan sanal işlevler de sanal işlevler.

+11

@Yossarian 'dan türetilmiş olmanız durumunda sizi şaşırtmak, bu yüzden sanal olarak türetilmiş sınıflardaki sanal işlevleri açıklamak için iyi bir uygulama sayılır. Etkili C++ kitabında bunu tartışır. –

+0

Türetilmiş yöntemlerde sanal işaretlemenin onları sanal olarak sonlandıracak bir yer olduğunu duydum. Üçüncü seviye türevini sanal olmayan bir geçersiz kılma yapar. ama Tadeusz'un standartlarının özünün bu dolaylı olarak “bu dolaylı” kelimesinden dolayı yanlış olduğunu kanıtladığını düşünüyorum. –

+2

@ v.oddou "Bir yerlerde duydum" insanların bir yerlerde "duydukları şeyler" genellikle yanlıştır. ;-) Aynı imzaya hiyerarşide daha yüksek olan "virtual" _somewhere_ işaretli bir işlev olduğu sürece, aynı imzaya sahip türetilmiş işlevler bir geçersiz kılmadır. 'Sanal' içeren bildirimin alakalı olmadığı 'boşluklar', anahtar kelimenin en temel görünümünden sonra boş anlambilimine sahip. –

0

Sen e nesnenin herhangi kopyasını oluşturarak ve d koyarak değildir. Yani d.foo() normal polimorfik davranışı izler ve türetilmiş sınıf yöntemini çağırır. Temel sınıfta sanal olarak bildirilen bir yöntem de türetilen sınıfta otomatik olarak sanal olur. kimse davranmaya beklediğiniz gibi

-1

çıkışı ("E") tam olarak davranır.

Nedeni: Bu referansın dinamik (çalışma zamanı) türü D'dir. D'ye statik bir yükseliş yapıyorsunuz, ancak bu, nesnenin gerçek türünü değiştirmiyor. Bu durumda, E sen başlatmasını edildi tipi, davranışını bkz: Sanal yöntemler ve dinamik harekât arkasında çok fikir

.

İlgili konular