6

Belli bir görevle ilgili bir sorun yaşıyorum, bu bir deneme, gerçek bir program değil. Görev, Compliler tarafından üretilen bir kopya kurucusunun olduğu gibi davranan D yapısının bir kopya kurucusunu tanımlamaktır.Birden fazla kalıtımın neden olduğu C++ 'da bir kopya kurucusunun muazzam çağrısı

class Ob{ 
}; 

struct A { 
Ob a; 
}; 

struct B : A { 
Ob b; 
}; 

struct C : A, B { 
Ob c; 
}; 

struct D : C, A { 
Ob d; 
}; 

Eğer yapı bir dolaylı böyle bir kopya kurucu bir tanımı belirsizlik neyin sebep Ge yapısında birkaç kez türetilmiştir görebileceğiniz gibi:

D(const D& _d) : C(_d), A(_d), d(_d.d) {} 

Sorum bu kopyayı nasıl tanımlanacağı olduğunu kurucu doğru mu? Yukarıda belirtilen tanımsız kod derleniyor, bu yüzden mümkün olması gerektiği görünüyor.

MinGW 4.8.1 hata iletisi:

zad3.cpp:12:8: warning: direct base 'A' inaccessible in 'C' due to ambiguity  [enabled by default] 
struct C : A, B { 
     ^
zad3.cpp:16:8: warning: direct base 'A' inaccessible in 'D' due to ambiguity  [enabled by default] 
struct D : C, A { 
    ^
zad3.cpp: In copy constructor 'D::D(const D&)': 
zad3.cpp:17:38: error: 'A' is an ambiguous base of 'D' 
D(const D& _d) : C(_d), A(_d), d(_d.d) {} 
            ^

ÖNEMLİ HATIRLATMA: Bu BİR DUPLICATE soru "çoklu miras neden Inaccessible doğrudan üssü" olduğunu Farklı erişim belirleyicileri ile ortak temel sınıfları hakkındaydı ve sonunda bir dönüşüm sorunu nedeniyle oldu. Burada aynı görünürlük ile birkaç kez miras alınan ortak bir temel için gerekli bir başlatıcıyı ayırmakla ilgilidir.

+0

Tam derleyici hata mesajını ekleyebilir misiniz? – Angew

+0

Ohh Anladım, yee derleyici hatası plz. –

+0

Belki bu yararlıdır: http://stackoverflow.com/questions/6488772/refer-base-class-members-from-derived-class – Jack

cevap

0

Derleyici tarafından oluşturulan kopya kurucusu, büyük baba temel sınıfının varsayılan yapıcısını çağırırdı. Muhtemelen istediğin bu değil. Sadece kopya kurucularla temiz bir tasarıma sahip olmak için, her sınıfın kopya kurucusunu uygulamanız ve ihtiyaç duyduğunuzdan emin olmanız gerekir.

Ama seni başlamak için, ve exercice'da belirsizlik sorunların çoğunu önlemek için: Geçerli hiyerarşi örnekte, A'ya doğrudan D

A(const A& other), a(other.a) { 
} 
//... 
B(const B& other) : A(other), b(other.b) { 
} 
//... 
C(const C& other) : B(other), A((const B)other), c(other.c) { 
} 
//... 
D(const D& other) : C(other), A((const B)other), d(other.d) { 
} 

ayrıntılı düzenlemeyi döküm olamaz virtual inheritance kullanmış olmalı.

Sizin durumunuzda, C'den A'ya doğru muğlak bir yol var: ya C-> A veya C-> B-> A Hiyerarşide ortak bir ata olarak A'yı bildirmek için, B'den miras olarak beyan edersiniz veya sanal olarak C'den A'ya. Ayrıca, D'den A'ya doğru muğlak bir yol var: ya D-> A ya da (D-> C-> A veya D-> C-> B> A). Yani, D'den A'ya devralmayı sanal olarak da beyan edersiniz.

struct B : public virtual A { ... } 
struct C : public virtual A, public B { ... } 
struct D : public C, public virtual A { ... } 

Şimdi tek hiyerarşinizdeki A'nın örneğini paylaştı yoktur. İstediğin kadar sonra, D kopya kurucu yazabilirsiniz:

D(const D& other) : C(other), A(other), d(other.d) 

üye D :: A :: D :: C :: A :: a veya D aynı olacaktır :: C :: B :: A :: a.

+0

Evet, derler. ** Ama ** burada sanal üsler olmadan ** birden fazla kalıtım var **. Bu kopya oluşturucuda, yalnızca B tabanından B mirasını nasıl kopyalayacağınızı tanımlarsınız. Bu, A'nın temelini doğrudan miras almaz, ne de C'nin miras aldığı A tabanını kopyalamaz! Bu iki varsayılan kurucu ile initalized olsun! – Christophe

+0

Bu, varsayılan kopya oluşturucusuna eşdeğer değil. – sth

+0

Evet, ilk cevabım doğru değildi. Tamamladım. – chrphb

5

DİKKAT: ANSWER TEMEL DÜZENLENMİŞTİR!Analiz sorunun

: Sen multiple inheritance with a diamond problem kullanıyorsunuz

. bir kez doğrudan (struct D: C,A) ve iki kez dolaylı (C miras yoluyla):

Daha spesifik olarak, sizin yapısı D aynı temel A sınıf üç kez devralır. temel sınıfları sanal değildir zamanda, D. 11 C++ standart bölümü 3 farklı bir alt-nesneler 10,1/4-5 aramaları bu kafes:

inheritance diagram

Normalde, her A üyesini, derleyiciye, atıfta bulunduğunuz 3 A alt nesnesinden hangisini anlatan açık bir kalifikasyonla ayırırsınız. Bu, C++ 11 bölüm 10.1/5'da açıklanmıştır. Üyeler için sözdizimi D kapsamı içinde A::a, C::a ve B::a olmalıdır, her ikisi de önce dışardaysanız D:: olmalıdır.

Maalesef C++ 11 bölüm 10.2/5-6 üye ad arama mantığı doğrudan A baz daima açık yeterlilik (hatta using ifadeleri) rağmen, diğer dolaylı A bazlar belirsiz hale getirecek olmasını sağlar.

Kesin çözüm:

sorun doğrudan temel sınıf kaynaklanır gibi

ve diğerlerinden bu bir diambiguate için hiçbir yolu vardır aslında, sadece gerçekten çalışma çözüm boş kullanmaktır MSVC2013, clang 3.4.1 ve gcc 4.9 ile

struct Ob{ int v; }; // v aded here to allow verification of copy of all members 
struct A { Ob a; }; 
struct B : A { Ob b; }; 
struct A1 : A {};  // intermediary class just for diambiguation of A in C 
struct C : A1, B { Ob c; }; // use A1 instead of A 
struct A2 : A { };  // intermediary class just for diambiguation of A in D 
struct D : C, A2 {  // use A2 instead of A 
    Ob d; 
    D() { } 
    D(const D& _d) : C(_d), A2(_d), d(_d.d) { } 
}; 

int main(int ac, char**av) 
{ 
    cout << "Multiple inheritance\n"; 
    D x; 
    x.A2::a.v = 1; // without A2:: it's ambiguous 
    x.A1::a.v = 2; // without A1:: it's ambiguous 
    x.B::a.v = 3; 
    x.b.v = 4; 
    x.d.v = 5; 

    D y = x; 
    cout << "The moment of truth: if not 1 2 3 4 5, there's a problem!\n"; 
    cout << y.A2::a.v << endl; 
    cout << y.A1::a.v << endl; 
    cout << y.B::a.v << endl; 
    cout << y.b.v << endl; 
    cout << y.d.v << endl; 
} 

Bu kod derler ve işi: Arabulucu sınıfı farklı bir ad zorlamak için.


Diğer (olmayan) çözümleri:

Benim önceki cevabı sadece açık yeterlilik dayanıyordu. Birçok eleştiriye rağmen, MSVC2013'te gerçekten derlenmiş ve başarıyla test edilmiştir. Ancak, garip bir şeydi: Editörün zekasında bir belirsizlik vardı, ancak derleme herhangi bir hata olmadan gayet iyiydi. Bunun bir intelisence hatası olduğunu düşündüm, ama şimdi bunun bir derleyici olmayan uyum olduğunu fark ettin (hata?)

D(const D& other) : C(other), A((const B)other), d(other.d) derlemesi yanıt veriyor ama testi geçmiyor. Niye ya ? Çünkü A((const B)other), other'u B olarak anlayacaktır. Bu nedenle D numaralı telefondan A doğrudan B'dan (A) başka bir şekilde alınan A değeri ile başlatılacaktır. Bu son derece iğrenç bir hatadır ve farkına varmam biraz zaman aldı.

Tabii ki sanal temel sınıflarını kullanabilirsiniz. Daha sonra, birçok problemi çözen, D'de sadece tek bir A alt nesne olacaktır.Ancak ne tasarladığınızı ben çizmiyorum ve bazı tasarımlar sanallaştırılmış bir elmastan ziyade bir kafes gerektiriyor.

İki adımlı bir kopyayı (adım 1: tablonun varsayılan olarak başlatılması; 2. adım: hedef değerin üssün üzerine kopyalanması) karşılayabiliyorsanız, doğru tablonun referansını döndüren farklı yönlendirme işlevlerini kullanan yaklaşımlar vardır. Ancak bu, yukarıda sunulan basit çözümden daha zor ve hataya eğilimli olabilir.

+1

Zaten bunu denedim, bir şekilde benim için makul görünüyordu ama ne yazık ki ne de MinGW 4.8.1'de ne de Microsoft Visual C++ 2013'te derleme yapmıyor.Her iki derleyici de benzer hata iletileri üretir: 'A', 'D' nin belirsiz bir tabanıdır ve 'A' sınıfı zaten başlatılmıştır – borrisso

+1

Önerilen çözüm derlenmez. Temel sınıfı başlatmak için 'A' alt nesne '_d' kullanılmalıdır. – sth

+0

Yukarıdaki kodun tamamını MSVC 2013'te derledim. Ancak dikkat: intellisense, kod oluşturma tarafından bildirilmeyen belirsizlik için bir hataya işaret etti. Ve derlenmiş kod mükemmel çalıştı (gerektiği gibi, çünkü geçerli bir yapı). – Christophe

İlgili konular