2017-09-01 1 views
0

J'essaie d'imiter l'implémentation .Net d'une liste générique en C++. DèsProblèmes d'héritage de modèle C++ (avertissements et erreurs)

template <typename T> 
class List : public IList<T>, public ICollection<T> { 

public: 
    List(void); 
    List(int32_ capacity); 

    // ICollection<T> 
    void Add(T item); 
    // other functions from ICollection 

    // IList<T> 
    T Item(int32_t index); 
    // other functions from IList 

    void AddRange(IList<T> items); 

private: 
    typedef vector<T> ListType; 

    ListType *m_pList; 
}; 


template <typename T> 
List<T>::List(void) { 
    m_pList = new ListType(); 
} 

template <typename T> 
void List<T>::Insert(uint32_t index, T item) { 
    // Insert an entry into the list at the specified offset 
    m_list->insert(index, item); 
} 

// Implementation of other functions here... 

comme:

J'ai étoffé les différentes classes abstraites virtuels comme purement interfaces comme suit:

template <typename T> 
class ICollection { 

public: 
    virtual void Add(T item) = 0; 
    virtual void Clear(void) = 0; 
    virtual bool Contains(T item) = 0; 
    virtual void Remove(T item) = 0; 

    virtual int32_t Count(void) const = 0; 

}; 

template <typename T> 
class IList : public ICollection<T> { 

public: 
    virtual T Item(int32_t index) = 0; 
    virtual int32_t IndexOf(T item) = 0; 
    virtual void Insert(int32_t index, T item) = 0; 
    virtual void RemoveAt(int32_t index) = 0; 

}; 

Maintenant, lorsque je tente de mettre en œuvre ma classe principale List comme suit J'essaie d'utiliser la classe List<T> comme suit:

List<int32_t> myList; 

Un avertissement se disant:

In instantiation of 'class List<long int>': 
    required from here 
warning: direct base 'ICollection<long int>' inaccessible in 'List<long int>' due to ambiguity [enabled by default] 

class List : public IList<T>, public ICollection<T> { 
    ^

Suivi par l'erreur suivante:

In instantiation of 'void List<T>::Insert(uint32_t, T) [with T = long int; uint32_t = long unsigned int]': 
    required from here 
error: no matching function for call to 'std::vector<long int, std::allocator<long int> >::insert(uint32_t&, long int&)' 

m_list->insert(index, item); 
^ 

note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::iterator, const value_type&) [with _Tp = long int; _Alloc = std::allocator<long int>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<long int*, std::vector<long int, std::allocator<long int> > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = long int*; std::vector<_Tp, _Alloc>::value_type = long int] 

vector<_Tp, _Alloc>:: 
^ 

note: no known conversion for argument 1 from 'uint32_t {aka long unsigned int}' to 'std::vector<long int, std::allocator<long int> >::iterator {aka __gnu_cxx::__normal_iterator<long int*, std::vector<long int, std::allocator<long int> > >}' 

Si je modifie la déclaration de la classe List<T> de façon à éliminer les classes abstraites IList<T> et ICollection<T>, aucune erreur ne généré.

Je devine que la façon dont j'utilise les classes de base modélisées n'est pas correcte dans ce cas.

+1

Vous avez plusieurs problèmes: 1) Les objets en C++ ne fonctionnent pas comme les objets .NET ou Java, ils sont fondamentalement différents 2) Héritage multiple. Pour plus d'informations, obtenez un bon livre C++. Ce sont des concepts fondamentaux qui ne peuvent pas être entièrement expliqués dans une brève réponse stackoverflow.com. Essayer d'apprendre le C++ en s'appuyant sur votre connaissance de .NET est une recette pour l'échec et la confusion sans fin parce que, comme je l'ai dit, les objets C++ fonctionnent complètement différemment.Saviez-vous, par exemple, que toutes vos méthodes doivent prendre une référence 'const' en tant que paramètre, et non une valeur? Voir votre livre C++ pour la raison pourquoi. –

+0

Merci pour vos commentaires. 1) Je comprends parfaitement cela. 2) Je n'ai pas besoin d'un bon livre et je n'essaie pas d '"apprendre le C++" mais j'essaie de comprendre pourquoi le système de templates ou ma mise en oeuvre, dans ce cas crée des erreurs dues à l'héritage multiple. Ne comptant pas sur la connaissance de .Net - en fait, je ne l'ai pas touché depuis un bon moment. – weblar83

+0

https://stackoverflow.com/questions/4118412/inaccessible-direct-base-caused-by-multiple-inheritance –

Répondre

1

Ce problème n'est pas directement lié aux modèles.

class A { 
    public void f() {} 
}; 

class B : public A {}; 

class C : public A, public B {}; 

int main() { 
    C c; 
    c.f(); // Error: ambiguous base class! 
} 

Lorsque vous héritez d'une classe, la classe dérivée contient un objet pour la classe de base, appelée une classe de base sous-objet. Donc, dans mon exemple, chaque B contient un A. Et chaque C contient un A et un B. Le problème est que lorsque j'essaie d'appeler f en tant que membre de C, le compilateur doit trouver le sous-objet A pour l'appeler. Mais il y a deux sous-objets avec ce type! L'un est directement hérité par C, et l'autre est à l'intérieur du sous-objet B hérité. Le compilateur ne peut donc pas comprendre ce que je veux dire.

La solution dans ce cas est de ne pas hériter deux fois d'une classe. Dans mon exemple, C n'a pas besoin d'hériter directement A, puisque l'héritage B lui fournira un sous-objet indirect A et un accès à tous ses membres. Dans votre cas, List<T> n'a pas besoin d'hériter directement de ICollection<T>. Il suffit juste de dériver de IList<T>. (Dans d'autres cas, il peut être utile d'utiliser "l'héritage virtuel", qui dit au compilateur "de ne créer qu'un sous-objet de classe de base pour ce type, même si je l'hérite indirectement plus d'une fois dans une classe dérivée". Mais cela peut être exagéré pour votre code tel quel.)

+0

Merci pour votre commentaire. Comprenez bien que vous n'avez pas besoin d'hériter de 'ICollection ', je n'étais pas sûr de la visibilité des fonctions 'ICollection ' de la classe 'List ' mais étant donné que c'est marqué 'public', c'était un peu évident. – weblar83