15

Şu anda C++ 'da Kalıtımın özelliklerini öğreniyorum ve yeni öğrenilen Sanal Temel derslerini test etmek istedim. ,C++ 11'de tek tip başlatım, sanal temel sınıflarla garip davranıyor?

Instantiating A via C 
Instantiating B. 
Instantiating C. 

Ama B{p_value1, p_value2} olarak değiştirdim an: Bu bana istenen çıktıyı verdi

#include <iostream> 

using namespace std; 

class A 
{ 
private: 
    int m_value; 
    string m_caller; 
public: 
    A(int p_value, string p_caller) : m_value{p_value}, m_caller{p_caller} 
    { 
     cout<<"Instantiating A via "<<m_caller<<endl; 
    } 
}; 

class B : virtual public A 
{ 
private: 
    int m_value; 
public: 
    B(int p_value1,int p_value2) : A{p_value1,"B"}, m_value{p_value2} 
    { 
     cout<<"Instantiating B."<<endl; 
    } 
}; 

class C : public B 
{ 
public: 
    C(int p_value1,int p_value2) : A{p_value1,"C"}, B(p_value1, p_value2) 
    { 
     cout<<"Instantiating C."<<endl; 
    } 
}; 

int main() 
{ 
    C c1(1,2); 
    return 0; 
} 

unutmayın sınıf C yapıcısı içinde B(p_value1, p_value2): Aşağıdaki basit bir kod çalıştı Ben şu çıktıyı aldım:

Instantiating A via C 
Instantiating A via B 
Instantiating B. 
Instantiating C. 

ben cevap arayan çalıştı, ancak tüm cevaplar bazı C++ standartları alıntı var . OOP'larda yeni başlayan biri olmak, bu davranış için daha basit bir açıklama arıyorum. Çok teşekkürler!

P.S. Windows'da derleyici g ++ 4.8.1 ile C :: B kullanıyorum.

+3

Bilginize, Tarif ettiğiniz davranışı gösteren ++ 3.7 tınlamak. Her iki versiyon da aynı çıkışı yayar (ilk). – WhozCraig

+0

İkinci durumda kopya kurucuyu çağırıyorsunuz. OP doğrudan 'A' kurucusunu çağırmayı olmasaydı en türetilmiş sınıf sanal taban sınıflar başlatılıyor sorumludur @UpAndAdam – lorro

+3

, kod derlemek olmaz. Ve bu nedir? Dönüştürülmüş dizgisi değişmezlerinde (ints) oldukları gibi * nedir? – Praetorian

cevap

8

Bu, g ++ 'da bir derleyici hatasıdır.

C++ 14 (N4140) bölümünde [dcl.init.list], liste başlatma tanımı (özlü için düzenlenmiş) olup içinde

: bir nesnenin ya da tip T referansının

listesi-başlatma T bir agregat olan

  • ise başlatıcı liste herhangi bir öğe ve T varsayılan kurucu bir sınıf tipi ise, toplam başlatma Aksi
  • gerçekleştirilir: aşağıdaki gibi tanımlanır Nesne, değeri başlatıldı. T std bir uzmanlık :: initializer_list, eğer T bir sınıf türüyse
  • Aksi takdirde, [...]
  • Aksi halde, kurucular olarak kabul edilir. Uygulanabilir kurucular numaralandırılır ve en iyisi aşırı yük çözünürlüğü ile seçilir. Herhangi bir argümanı dönüştürmek için bir daraltma dönüşümü gerekiyorsa, program kötü biçimlendirilir.

ilk 3 puan

  • [...]
  • geçerli değildir: B (toplam temel sınıfları olamaz) bir toplamı değildir, başlatıcı listesi unsurları var B bir uzmanlık değil std::initializer_list. Hiçbir canlı başlatıcı listesi yapıcısı bulunursa

    , aşırı yük çözünürlük gerçekleştirilir: aşırı yük çözünürlük [over.match.list] /1.2 göre yapıcı B(int, int) için B{p_value1, p_value2} eşleştiği için

    dördüncü nokta geçerlidir Yine, aday fonksiyonlar T sınıfının tüm kurucularıdır ve argüman listesi başlatıcı listesinin elemanlarından oluşur.

    O B(whatever) ve B{whatever} aynı şekilde davranması gerektiğini son teklif gelen izler.

    +0

    Mükemmel cevap! Teşekkürler :) – SimplyOm