2014-10-29 9 views
11

Bir kurucu başlatma listesinde {} başlatma, soyut türlere başvuruyu başlatırken() başlangıçtan farklı mıdır? Aşağıdaki sınıf Bar atın:Neden parens initializaton yaptığı zaman C++ 11 kurucu başlatma listesinde kıvırcık kaşlılık başlangıç ​​işlemi çalışmıyor?

class AbstractBase 
{ 
public: 
    AbstractBase() {} 
    virtual ~AbstractBase() = default; 

    virtual void ab() = 0; 
}; 

class Foo : public AbstractBase 
{ 
public: 
    Foo() {} 

    void ab() {} 
}; 

class Bar 
{ 
public: 
    Bar(const AbstractBase& base) : myBase{base} {} 

private: 
    const AbstractBase& myBase; 
}; 


int main() 
{ 
    Foo f{}; 
    Bar b{f}; 

} 

derleme, ben hatayı hattını derler ve iyi çalışır

Bar(const AbstractBase& base) : myBase(base) {} 

değiştirilmesi

test5.cpp: In constructor ‘Bar::Bar(const AbstractBase&)’: 
test5.cpp:22:48: error: cannot allocate an object of abstract type ‘AbstractBase’ 
    Bar(const AbstractBase& base) : myBase{base} 
               ^
test5.cpp:2:7: note: because the following virtual functions are pure within ‘AbstractBase’: 
class AbstractBase 
    ^
test5.cpp:8:18: note: virtual void AbstractBase::ab() 
    virtual void ab() = 0; 

olsun.

Stroustrup'un C++ 11 kitabını okurken, std :: initializer_list <> ve diğerlerini alan kurucular arasında bir belirsizlik bulunmadığı durumlar hariç, çoğu durumda {} 'nın() ile aynı olduğu izlenimindeydim. Kurucular ve türlerin otomatik olarak kullanıldığı durumlar, bunların hiçbiri burada yapıyorum.

+1

Başparmak kuralı: Öğeleri (sıfır dahil) içeren listeler için '{}' ve diğer kurucuları açıkça çağırmak için '()' kullanın. –

+1

Aslında bu, referansların listesi başlatılmasıyla ilgili bir sorundur –

+0

Aynı sorun burada olduğu gibi - http://stackoverflow.com/questions/19347004/copy-constructor-curly-braces-initialization –

cevap

12

Kısa yanıt: Bu, C++ 14'te giderilen Standartta bir hataydı ve g ++ 4.9 düzeltme eki (geriye dönük olarak C++ 11 moduna da uygulandı). , S const &y {x}; anlamı değil x için y bağlamak için C++, 11 Metinde

struct S 
{ 
    int x; 
    S() { }  // this causes S to not be an aggregate (otherwise aggregate 
       // initialization is used instead of list initialization) 
}; 

S x = 5; 
S const &y { x } ;  

x = 6; 
std::cout << y << std::endl;  // output : 5 

;: Defect Report 1288


İşte basit bir örnek aslında anlam, bir geçici oluşturmak ve buna bir referans vermek. C++, 11 [dcl.init.ref]/3'ten:

Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is list-initialized, and the reference is bound to that temporary. [Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. —end note ]

Bu, açık bir şekilde, bu kod amacı x doğrudan y bağlamak için oldukça saçma edilir. 14 C++ metin değiştirildi: bir tür yana

Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element;

referans ilişkili kendisi (veya temel sınıflarında) etmektir, burada benim numunede ve gerçek kodunda, aslında doğru bağlamak gerekir .


Kişisel hata mesajı C++ 11 dilini takiben ve referans bağlanma base geçici bir oluşturulmaya çalışılırken derleyici gelir; ve bu başarısız olur çünkü base soyut bir tiptir.

+0

{} başlatma kullanırken const referansı kaldırırsam, farklı bir hata alıyorum: 'test5.cpp: Yapıcı 'Bar :: Çubuk (SoyutBase &)': test5 .cpp: 22: 42: hata: '<Özet-kapalı başlatıcı listesi>'Bar (SoyutBase & base) türünde bir değerden 'AbstractBase &' türünün const olmayan başvurusunun geçersiz başlatılması: myBase {base} {} ^ ' –

+3

@oryan_dunn, bir const olmayan referansa geçici olarak bağlanmayı deniyor –

+0

Evet, şimdi, soyut bir türden bir geçici yapmaya çalışıyorum. Sanırım C++ 14 gelene kadar tutarlı olmaya devam etmek için tüm kurucu başlatma listelerinde() kullanmaya devam etmem gerekecek. –

İlgili konular