2011-03-20 12 views
44

aşağıdaki pasajı derleme sırasında hata "foo kuşkulu çağrı" bir üretir ve bu soruna herhangi bir yolu varsa tam foo çağrısı niteleme olmadan bilmek istiyorum:Neden aynı ada sahip birden fazla kalıtımsal işlevler, ancak farklı imzalar aşırı yüklenmiş işlevler olarak ele alınmıyor?

Yani
#include <iostream> 

struct Base1{ 
    void foo(int){ 
    } 
}; 

struct Base2{ 
    void foo(float){ 
    } 
}; 

struct Derived : public Base1, public Base2{ 
}; 

int main(){ 
    Derived d; 
    d.foo(5); 

    std::cin.get(); 
    return 0; 
} 

, soru başlık diyor. Fikirler? Demek istediğim, aşağıdaki işlemler kusursuz olarak çalışır:

+2

iki foo (ikinci durumda) içinde hangi işlevin çağrıldığını sabitlemek için günlüğe kaydetme ifadeleri eklerseniz, şaşıracaksınız ... C++, arcane kuralıyla dolu;) –

+1

@Matthieu: * gasp *! Lanet kuralları saklıyor. :( – Xeo

cevap

42

üye arama kuralları 10,2/2

Aşağıdaki adımlar, bir sınıf kapsamındaki C adı arama sonucu tanımlar bölümünde tanımlanmıştır. İlk olarak, sınıftaki ve temel sınıftaki alt nesnelerinin her birinde ad için yapılan her deklarasyon dikkate alınır. B'un bir alt nesnesindeki f numaralı üye adı, AA alt nesnesinin alt nesnesini B temel bir alt nesnesi olarak kaydeder. Bu kadar gizli olan tüm bildirimler dikkate alınarak yok edilir. Bir kullanma-bildirimi ile tanıtılan bu bildirimlerin her biri, bildirim-bildirimi ile belirtilen bildirimi içeren türden C'un her bir alt nesnesi olarak kabul edilir. Sonuç bildirimleri tümü aynı türde alt nesnelerden değil ya da kümenin tekdüze olmayan bir üyesi varsa ve farklı alt nesnelerden üyeler içeriyorsa, bir belirsizlik var ve program hatalı biçimlendirilmiş. Aksi halde, bu ayar arama sonucudur.

class A { 
public: 
    int f(int); 

}; 
class B { 
public: 
    int f(); 

}; 
class C : public A, public B {}; 
int main() 
{ 
    C c; 
    c.f(); // ambiguous 
} 

Yani o belirsizlik void foo(float) C'nin kapsamı içindedir çünkü ikinci kod sorunsuz çalışır

class C : public A, public B { 
    using A::f; 
    using B::f; 

}; 

int main() 
{ 
    C c; 
    c.f(); // fine 
} 

çözmek için using beyanlarını A::f ve B::f kullanabilirsiniz. Aslında d.foo(5);, void foo(float) numaralarını ve int sürümünü çağırmaz.

+2

'void foo (float) 'versiyonu çağrılıyor bana gerçekten var .. kapsamlı cevabınız için teşekkürler. :) – Xeo

+1

Akla gelen tek bir şey var ... saklamak isteyeceği bir durum var. Temel sınıf işlevleri farklı imzalara sahiplerse? Aynı imza fonksiyonları için, bu, yararlı, ama farklı olanlar için iyi bir örnek hayal bile edemiyorum ... – Xeo

+0

+1. Çok hoş. Bunu bilmiyordum. Teşekkürler Prasoon. :-) – Nawaz

2

İşe yarayacak mı?

struct Derived : public Base1, public Base2{ 
    using Base2::foo;} 
2

İsim arama, aşırı yük çözünürlüğü için ayrı bir fazdır.

Önce ad arama işlemi gerçekleştirilir. Bu, ismin hangi kapsamın geçerli olduğuna karar verme sürecidir. Bu durumda, d.foo'un d.D::foo veya d.B1::foo veya d.B2::foo anlamına mı karar vermesi gerekir. İsim arama kuralları, işlev parametrelerini veya herhangi bir şeyi dikkate almaz; sadece isimler ve kapsamlar ile ilgili.

Yalnızca bu karar verildikten sonra, adın bulunduğu yerde işlevdeki farklı aşırı yüklenmeler üzerinde aşırı yük çözünürlüğü uygularız mı?

Örneğinizde, böyle bir işlev varsa, numaralı telefonu arayarak D::foo() numaralı telefonu bulabilirsiniz. Ama hiç yok. Böylece, kapsamları geriye doğru çalıştırarak, temel sınıfları dener. Artık foo, B1::foo veya B2::foo'a eşit olarak bakabiliyor, bu yüzden belirsiz.

Aynı nedenden dolayı, D üye işlevinin içinde belirsizliği olan foo(5);'u belirsiz kılmaya çalışırsınız.


önerilen çözümün etkisi:

struct Derived : public Base1, public Base2{ 
    using Base1::foo; 
    using Base2::foo; 

bu adı D::foo oluşturur ve iki işlevi tespit sağlamasıdır. Sonuç, d.foo'un d.D::foo'a çözüldüğü ve daha sonra D::foo tarafından tanımlanan bu iki işlevde aşırı yüklenmenin ortaya çıkabileceğidir.

Not: Bu örnekte D::foo(int) ve Base1::foo(int), bir işlev için iki tanımlayıcıdır; ama genel olarak, isim arama ve aşırı yükleme çözümleme işlemi için, iki ayrı işlev olup olmadıkları fark etmez.

İlgili konular