2015-07-07 26 views
9

Kalıtım, sanal işlevler ve işlev aşırı yüklenmesini anladığımı sanıyordum, ancak bu özellikler arasındaki etkileşim hakkında bir şeylerin beni uyandırdığı bir durum var.Aşırı yüklü sanal işlevler kümesinin kısmi kalıtımı

ben aşırı yüklenmiş bir sanal işlevi içeren basit bir temel sınıf ve ondan türetilen ikinci bir sınıf var varsayalım:

class b { 
public: 
    virtual int f() { return 1; } 
    virtual int f(int) { return 2; } 
}; 


class d : public b { 
public: 
    virtual int f(int) { return 3; } 
}; 

Bildirim türetilmiş sınıfa o d geçersiz kılmaları aşırı sanal fonksiyonlarının tek.

ben sınıfın d bir nesne örneğini ve üzerinde hiçbir problem f(int) çağırabilirsiniz:

d x; 
std::cout << x.f(0) << std::endl; 

Ama çalıştığınızda 0-argüman işlevi çağırmak için: İşlem başarısız

std::cout << x.f() << std::endl; 

! gcc, "d :: f() 'öğesine çağrı için eşleme işlevi yok"; adaylar şunlardır: virtual int d :: f (int) ". clang diyor ki, "çağrıya cevap vermek için çok az argüman var, beklenen 1, 0 tane var mı?" demek istediniz "b :: f"? " d, 0-argüman f() yöntemine sahip olan b'dan türetilmiş olsa da, derleyici bunu görmezden gelir ve bunun yerine d '1 argüman yöntemini çağırmaya çalışır.

Ben türetilmiş sınıftaki 0-argüman fonksiyonunun tanımını tekrarlayarak bu düzeltebilirsiniz

:

class d : public b { 
public: 
    virtual int f() { return 1; } 
    virtual int f(int) { return 3; } 
}; 

Veya, clang en hata mesajı önerdiği gibi, ben aptal bir netleştirme sözdizimi ben asla kullanabilirsiniz

std::cout << x.b::f() << std::endl; 

Ama benim soru, ben kırdınız ne kuralı ve bu kuralın/zorlamak korumaya çalıştığı şey/savunmak: çalışacak tahmin? Burada yapmaya çalıştığımı sandığım şey, mirasın ne demek olduğunu düşündüğüm şeydi.

+0

bu konunun çok iyi bir tartışma için Başvuru http://stackoverflow.com/questions/1628768/why-does-an-overridden-function-in-the-derived-class -hide-diğer-aşırı-of-the – blade

cevap

7

Bu, gizleme adıyla adı olarak bilinir.

Türetilmiş sınıfta aynı ada sahip bir işlevi bildirdiğinizde, tabanda aynı ada sahip tüm işlevler gizlenir.

onlara niteliksiz erişebilmek için, türetilmiş bir sınıf içine using bildirimi ekleyin:

class d : public b { 
public: 
    using b::f; 
    virtual int f(int) { return 3; } 
}; 
+1

Bu standartlarda mı? –

+3

@OthmanBenchekroun [basic.scope.hiding]/1 'Bir isim, aynı adı taşıyan iç içe geçmiş deklarasyonlu bir bölgede veya türetilmiş bir sınıfta açık bir beyan ile gizlenebilir. ' – TartanLlama

+0

@OthmanBenchekroun Aynı örnekle birlikte 13.2 Beyan eşleştirmesi de ya da neredeyse yani) tarafından verilen Steve – marom

2

ek olarak bazı açıklama @ için TartanLlama cevabı: derleyici çağrı çözmek zorundadır

  1. İsim araması: f nedeniyle, sırayla üç ana şeyi gerçekleştirir. Başka bir şey yapmadan önce derleyici, f adlı en az bir varlığa sahip bir kapsam arar ve adayların listesini yapar. Bu durumda, ad arama ilk olarak kapsamında f adında en az bir üye olup olmadığını görmek için bakar; yoksa, temel sınıflar ve kapsayıcı ad alanları sırasıyla en az bir adayına sahip olan bir kapsam bulunana kadar tek tek değerlendirilecektir.Bu durumda, ancak, ilk kapsamı derleyici görünüyor zaten f adlı bir varlığa sahip ve sonra Ad arama durdurur.

  2. Aşırı yükleme çözünürlüğü. Daha sonra, derleyici 'u seçerek aday listesinden benzersiz en iyi eşleşmeyi seçmek için aşırı yük çözünürlüğü uygular. Bu durumda argüman sayısı uyuşmaz, bu yüzden başarısız olur.

  3. Erişilebilirlik denetimi. Son olarak, derleyici seçilen işlevin çağrılıp çağrılmadığını belirlemek için erişilebilirlik denetimi gerçekleştirir.

Name lookup

İlgili konular