2013-08-10 20 views
5

Ho tre classi strutturata in questo modo:Fixing C++ ereditarietà multipla chiamata ambiguo

#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; 
} 

Sto ottenendo il seguente:

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()

Ho letto un po 'di più sull'ereditarietà e so che ha molte insidie: questo è uno di questi. Ho bisogno che la mia struttura di classe sia così, quindi mi chiedevo se c'era un modo per risolvere questo problema usando i modelli?

Aggiornamento
Dopo aver letto i vostri commenti, il mio pensiero originale era che forse posso solo delineare tra un AddressType che è una CharacterKeyword e un AddressType che è una MeasurementKeyword dal templating del AddressType. E usandolo come tale nel codice aggiornato. O Posso solo specificare lo spazio dei nomi del membro che vorrei. Dal momento che il modo basato sui modelli non è stato ancora menzionato come risposta, è una cattiva soluzione? Devo solo specificare lo spazio dei nomi del membro che voglio?

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

dipende da come si vuole risolvere questo problema .. cosa vuoi che accada qui? –

+0

@KarthikT è per questo che gli ho dato entrambi i modi;) – aaronman

+0

@aaronman Yup, non sbaglio la tua soluzione, ma non sono sicuro di cosa vuole compiacere con i modelli .. –

risposta

13

Questo è causa di un diamond inheritance pattern, per risolvere l'errore è possibile specificare lo spazio dei nomi specifico che si desidera il membro da like.

paddressType->MeasurementKeyword::GetValue() 

o

paddressType->CharacterKeyword::GetValue() 

  1. Fondamentalmente la classe AddressType ha accesso ai GetValue membri di entrambe le classi da cui eredita e non è possibile scegliere una (chiamata è ambigua).
  2. Il scope resolution operator (::) consente di specificare quale si desidera effettivamente.
  3. Non hai detto cosa vuoi fare questo codice, quindi dirò semplicemente che i modelli di eredità generalmente complessi non favoriscono la creazione di codice leggibile, ripensano a ciò che realmente desideri.
3

In genere, quando si esegue il deadly diamond of death è un segno che è necessario ripensare il design. Tuttavia, se non è assolutamente possibile evitare questa situazione, C++ fornisce una soluzione sotto forma di virtual inheritance. L'ereditarietà virtuale risolve alcune delle "ambiguità dei diamanti", ma è anche goffo. Ad esempio, devi chiamare esplicitamente i costruttori non predefiniti del genitore nel costruttore della classe derivata.

Ancora una volta, il modo migliore è evitare il diamante in primo luogo. Ho programmato in C++ per molti anni e finora non ho mai avuto questo problema nel mio codice.

+0

"devi chiamare esplicitamente i costruttori del genitore nel costruttore della classe derivata". Vuoi dire che le classi di base virtuali sono inizializzate nella classe più derivata? Se nella classe base virtuale ci sono dei sensori predefiniti, non è necessario chiamarli esplicitamente. – dyp

+0

virtuale non risolve questo problema, la chiamata è ancora ambigua, sono d'accordo con il resto – aaronman

+0

@DyP Sì. Voglio dire che devi menzionare la classe dei genitori. – Dima

2

definire AddressType come questo:

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