2013-08-10 11 views
5

Mam trzy klasy skonstruowany tak:Mocowanie C++ Wielokrotne dziedziczenie Niejednoznaczne połączeń

#include <iostream> 
using namespace std; 

class Keyword 
{ 
    public: 
     virtual float GetValue() = 0; 
}; 

class CharacterKeyword : public Keyword 
{ 
    public: 
     virtual float GetValue(){return _value;} 
    private: 
     float _value; 
}; 

class MeasurementKeyword : public Keyword 
{ 
    public: 
     virtual float GetValue(){return _value;} 
    private: 
     float _value; 
}; 

class AddressType : public CharacterKeyword, public MeasurementKeyword 
{ 

    private: 
     float address; 
     float addresExt; 
}; 

int main() 
{ 
    AddressType *a = new AddressType(); 
    a->GetValue(); 
    return 0; 
} 

Otrzymuję następujący:

In function ‘int main()’:
error: request for member ‘GetValue’ is ambiguous
error: candidates are: virtual float Keyword::GetValue()
error: virtual float MeasurementKeyword::GetValue()
error: virtual float CharacterKeyword::GetValue()

Zrobiłem kilka czytania w wielu dziedziczeniu i wiem, że ma wiele pułapek - jest to jeden z nich. Potrzebuję mojej struktury klasowej, aby tak wyglądać, więc zastanawiałem się, czy istnieje sposób, w jaki mogę to naprawić za pomocą szablonów?

Aktualizacja
Po przeczytaniu komentarzy, moja oryginalna myśl, że być może po prostu wyznaczać między AddressType że jest CharacterKeyword i AddressType że jest MeasurementKeyword przez templating z AddressType. I używanie go jako takiego w zaktualizowanym kodzie. LUB Mogę tylko określić przestrzeń nazw członka, który chciałbym. Skoro szablonowy sposób nie został jeszcze wymieniony jako odpowiedź, czy jest to zła poprawka? Czy powinienem tylko określić przestrzeń nazw członka, którego chcę?

template <class T> 
class AddressType : public T 
{ 

    private: 
     float address; 
     float addresExt; 
}; 

int main() 
{ 
    AddressType<MeasurementKeyword> *a = new AddressType<MeasurementKeyword>(); 
    a->GetValue(); 
    return 0; 
} 
+1

Zależy jak chcesz to naprawić .. co chcesz się zdarzyć tutaj? –

+0

@KarthikT dlatego dałem mu obie strony;) ​​ – aaronman

+0

@aaronman Yup, nie ma nic przeciwko twojemu rozwiązaniu, ale nie jestem pewien, co chce osiągnąć z szablonami .. –

Odpowiedz

13

Wynika to z diamond inheritance pattern, aby rozwiązać ten błąd można określić konkretną przestrzeń nazw chcesz element z niczym.

paddressType->MeasurementKeyword::GetValue() 

lub

paddressType->CharacterKeyword::GetValue() 

  1. Zasadniczo klasa AddressType ma dostęp do GetValue członków z obu klas to dziedziczy i nie można wybrać jeden (wywołanie jest niejednoznaczna).
  2. The scope resolution operator (::) pomaga określić, który naprawdę chcesz.
  3. Nie powiedziałeś tego, co faktycznie chcesz zrobić, więc powiem, że generalnie złożone wzory dziedziczenia nie sprzyjają tworzeniu czytelnego kodu, przemyślenia tego, czego naprawdę chcesz.
3

Generalnie, gdy natrafisz na deadly diamond of death, jest to znak, że powinieneś przemyśleć swój projekt. Jednakże, jeśli absolutnie nie można uniknąć tej sytuacji, C++ zapewnia rozwiązanie w postaci virtual inheritance. Dziedziczenie wirtualne rozwiązuje niektóre z "niejednoznaczności diamentowych", ale jest również niezgrabne. Na przykład, musisz jawnie wywołać konstrukcje domyślne rodzica w konstruktorze klasy pochodnej.

Po raz kolejny najlepszym sposobem jest uniknięcie diamentu w pierwszej kolejności. Programowałem w C++ od wielu lat i do tej pory nigdy nie miałem tego problemu w moim kodzie.

+0

"musisz jawnie wywoływać konstruktory rodzica w konstruktorze klasy pochodnej". Masz na myśli, że wirtualne klasy bazowe są inicjowane w najbardziej pochodnej klasie? Jeśli w wirtualnej klasie bazowej istnieją domyślni ctors, nie trzeba ich jawnie wywoływać. – dyp

+0

virtual nie rozwiązuje tego problemu, połączenie jest nadal niejednoznaczne, zgadzam się z resztą – aaronman

+0

@DyP Tak. Chodzi mi o to, że musisz wspomnieć o klasie rodzica. – Dima

2

określić AddressType tak:

class AddressType : public CharacterKeyword, public MeasurementKeyword 
{ 
public: 
    using MeasurementKeyword::GetValue; 
private: 
    float address; 
    float addresExt; 
}; 
Powiązane problemy