2009-12-01 4 views
1

Je travaille sur un projet et il est dans une étape que je ne sais pas ce qui ne va pas. Voici la version simplifiée:Polymorphisme et tableau de problème de pointeurs en C++

Le code:

class Base {     // This base class is pure abstract 

    public: 
     virtual ~Base(); // Necessary to trigger destructors in inherited classes 
     virtual baseFunc() = 0; 
    }; 



    class DerivedA : public Base{ 

    public: 
     DerivedA(SomeClassUseBase * tmp){ 

     tmp -> register(this); 
     } 

     ~DerivedA(); 

     void baseFunc(){ 
      // do something here that's only for DerivedA   

     } 
    }; 



    class DerivedB : public Base{ 

    public: 

     DerivedB(SomeClassUseBase * tmp) { 
       tmp -> register(this); 
     } 

     ~DeriveB(); 

     void baseFunc(){ 
      // do something here that's only for DerivedB   

     } 
    }; 

    class SomeClassUseBase { 

     private: 
     Base ** basePrt; 
     unsigned int index; 

     public: 
     someClassUseBase(int num) { 

       basePrt = new Base*[num]; //create an array of pointers to the objects 
       index = 0; 
     } 

     void register(Base * base){ 

      //i tried *(basePrt[index]) = *base, but got the same problem 
      basePrt[index] = base; 

      index = index + 1; 

     } 

     void checkList() { 
      for (int i = 0; i < index ;i++){ 
      next = basePrt[i]; 

       next -> baseFunc(); //fails here 
     } 
     } 

    }; 

int main() { 

    SomeClassUseBase tmp = new SomeClassUseBase(5); 

    Base *b[5]; 

    for (i = 0; i < 5; i += 1) { 
     if (i % 2 == 0) { 
      b[i] = new DerivedA(&tmp); 
     } 
     else { 

      b[i] = new DerivedB(&tmp);   
      // the object pointed by tmp::basePrt[0] is lost after this line 
     } // if 



    } // for 

    tmp.checkList();  //crashes here since tmp.bastPrt[0] points to null 

} 

Le problème est que quand dans le principal, je tends la ligne lorsque la première DerivedB est créé, le pointeur DerivedA déjà créé par tmp.basePrt [0] est perdu un peu comment. Je ne sais pas pourquoi mais je soupçonne que cela a un rapport avec le polymorphisme? S'il vous plaît aider !! Merci!!

Edit:

N'a pas tout à fait obtenir le bon code la première fois, désolé ...

+0

Juste pour ajouter quelques détails à la question: un objet de SomeClassUseBase gardera un tableau de ptr aux objets de la classe de base, qui sera l'exécution soit DerivedA ptr ou DerivedB ptr. La raison pour laquelle tmp.register appelle (this) est d'ajouter self à cette liste. Et btw, tmp a une fonction publique Base ** getTheList(); , qui retournera le tableau de pointeurs aux objets Base, à nouveau (ce seront des pointeurs vers DerivedA/B à l'exécution) – derrdji

+1

Le code, tel que présenté, ne compile pas. Corriger les erreurs du compilateur et l'exécuter ne présente pas le problème que vous rencontrez. Peut-être devriez-vous vérifier que l'exemple que vous donnez démontre le problème que vous rencontrez.Je – Skizz

Répondre

3

Où se trouve le support de fermeture de la boucle?

void checkList() { 
    for (int i = 0; i < index ;i++){ 
     next = basePrt[i]; 

     next -> baseFunc(); //fails here 
    } // this one is missing in the example ! 

} 

Utilisez un vecteur ...

class SomeClassUseBase { 

private: 
    std::vector<Base*> basePrt; 

public: 
    void register(Base * base){ 
     basePrt.push_back(base); 
    } 

    void checkList() { 
     std::for_each(basePrt.begin(), basePrt.end(), std::mem_fun(&Base::baseFunc); 
    } 

};


Cela fonctionne pour moi. Ce n'est pas le code que j'écrirais pour mes projets mais ça fonctionne.

class SomeClassUseBase; 

class Base {     // This base class is pure abstract 

public: 
    virtual ~Base() {} // Necessary to trigger destructors in inherited classes 
    virtual void baseFunc() = 0; 
}; 

class DerivedA : public Base { 

public: 
    DerivedA(SomeClassUseBase * tmp){ 
     tmp -> registerIt(this); 
    } 

    void baseFunc(){ 
     // do something here that's only for DerivedA   
    } 
}; 

class DerivedB : public Base { 

public: 
    DerivedB(SomeClassUseBase * tmp){ 
     tmp -> registerIt(this); 
    } 

    void baseFunc() { 
     // do something here that's only for DerivedB   
    } 
}; 

class SomeClassUseBase { 

private: 
    Base ** basePrt; //Remark: use a vector or shared_array 
    unsigned int index; 
    SomeClassUseBase(const SomeClassUseBase&); 
    const SomeClassUseBase& operator=(const SomeClassUseBase&); 
public: 
    explicit SomeClassUseBase(int num) { 
     //Remark: Store the size of the container 
     basePrt = new Base*[num]; //create an array of pointers to the objects 
     index = 0; 
    } 

    ~SomeClassUseBase() { 
     delete[] basePrt; 
    } 
    void registerIt(Base * base) { 
     //Remark: what if index >= size of the array? 
     basePrt[index] = base; 
     index = index + 1; 

    } 

    void checkList() const { 
     for (int i = 0; i < index ;i++){ 
      Base *next = basePrt[i]; 
      next->baseFunc(); 
     } 
    } 

}; 

int main() { 

    SomeClassUseBase tmp(5); 
    Base *b[5]; //Remark: Use a smart_pointer 
    for (int i = 0; i < 5; i += 1) { 
     if (i % 2 == 0) { 
      b[i] = new DerivedA(&tmp); 
     } 
     else { 
      b[i] = new DerivedB(&tmp);   
     } // if 
    } // for 

    tmp.checkList();  

    for(int i = 0; i < 5; ++i) { 
     delete b[i]; 
    } 
} 
+0

ajouté quelques informations supplémentaires sur les raisons en utilisant tableau au lieu de vecteur, s'il vous plaît vérifier, je vous remercie – derrdji

+0

@derrdjii Alors pourquoi ne pas revenir un vecteur de pointeurs au lieu d'un tableau de pointeurs. – TimW

4

Vous créez les 5 objets (DerivedA/B) dans la base Array * b [5], mais dans votre liste() vous n'avez pas accès à ceux-ci. Essayez d'obtenir ce tableau en tmp ou d'instancier les objets DerivedA/B à l'intérieur de tmp. Dans la forme actuelle, les deux tableaux dans tmp et dans main() ne sont connectés nulle part et c'est pourquoi à l'intérieur de tmp vous avez toujours un tableau vide après avoir exécuté main().

Mise à jour

Vérifiez aussi que le type de index (entier non signé) membre correspond au type de votre variable de boucle i (actuellement entier). Ensuite, essayez est de faire vos méthodes explicitement le DerivedA/B également virtual (aussi destructor!). En fonction du compilateur, cela peut être un problème qui provoque la résolution de votre appel à baseFunc() vers le corps 'null' de la base. Enfin, si elle est vraiment C++, vous pouvez essayer de travailler avec des références, de sorte que vos constructeurs ressemblent

DerivedA(SomeClassUseBase& tmp) { 
    tmp.register(this); 
} 

Notez l'utilisation du point-opérateur au lieu de « -> », ça rend les choses un peu plus facile lire et maintenir.

+0

+1 Correct, la méthode SomeClassUseBase :: register de tmp n'est jamais appelée. Aussi, je suppose que la ligne "SomeClassUseBase tmp = new SomeClassUseBase (5);" devrait être "SomeClassUseBase * tmp = new SomeClassUseBase (5);" –

+0

@ Kosi2801: que voulez-vous dire par ne pas avoir l'accès? sont-ils juste un tableau de pointeurs? – derrdji

+0

SomeClassUseBase :: register est appelé dans le constructeur de DerivedA et DerivedB, l'autre est probablement une faute de frappe? –

Questions connexes