2008-10-25 8 views
12

je suis en train de compiler ce morceau très simple codeclasses C++ emboîtées me rend fou

class myList 
{ 
public: 
    std::vector<std::string> vec; 
    class Items 
    { 
    public: 
     void Add(std::string str) 
     { 
      myList::vec.push_back(str); 
     }; 
    }items; 
}; 

int main() 
{ 
    myList newList; 
    newList.items.Add("A"); 
} 

Que puis-je faire pour faire ce travail sans créer plusieurs objets qui ont besoin ou des trucs ...

trop compliquer
+3

venant de Java :-) –

Répondre

15

Ajoutez un couple de constructeurs et un pointeur vers la classe parente.

#include <string> 
#include <vector> 
class myList 
{ 
public: 
    std::vector<std::string> vec; 
    myList(): items(this) {} // Added 
    class Items 
    { 
    public: 
     Items(myList *ml): self(ml) {} // Added 
     void Add(std::string str) 
     { 
       self->vec.push_back(str); // Changed 
     }; 
     myList *self; //Added 
    }items; 
}; 

int main() 
{ 
    myList newList; 
    newList.items.Add("A"); 
} 

Vous devez le constructeur myList(), il enregistre les instances de lui-même avec l'instance de la variable membre de classe interne. Ensuite, vous avez besoin du constructeur Items pour stocker le pointeur sur l'instance externe de la classe myList. Enfin, dans la méthode Add, vous devez référencer vec dans l'occurrence myList stockée.

Comme Catskul souligne, le constructeur de l'article ne doit pas faire quoi que ce soit avec le pointeur myList qu'il reçoit. Je voudrais aussi dire que bien que cette réponse soit plus proche de l'intention originale, la réponse de steveth45 est plus proche de ce que vous voudriez faire dans un vrai programme.

+0

merci beaucoup, cela fonctionne, mais j'espérait qu'un version plus simple existé, mais je dois continuer à faire face à stuborness C++ :-(espoir C++ 0x résout certains de ces problèmes – SMeyers

+1

... mais attention à passer MyList ce pointeur pendant que MyList est encore en construction. se mettre en difficulté s'il fait quelque chose qui finit par utiliser le pointeur MyList trop tôt – Catskul

11

De cette façon, vous n'êtes pas d'exposer directement votre membres de la classe. Votre exemple semble sur-architecturé un peu. Pourquoi mettre un vecteur std :: dans une classe et l'exposer comme public?

class myList 
{ 
private: 
    std::vector<std::string> vec; 
public: 
    void Add(std::string str) 
    { 
     vec.push_back(str); 
    }; 
}; 

int main() 
{ 
    myList newList; 
    newList.Add("A"); 
} 
+2

L'auteur original a probablement besoin de la construction de classe interne pour d'autres choses qu'il ne mentionne pas (pour la simplicité de son exposition). sont d'ingénierie aspect doux compte tenu des informations existantes, mais le problème semble être un "jouet" abstraction des problèmes de compilation pour pourrait à l'origine avoir été un algorithme assez complexe. Ce n'est pas important vraiment, vous comprenez probablement déjà, je dis juste ... –

2

Les classes internes ne sont liées que par le nom. Vous ne pouvez pas faire référence au vecteur dans la classe de base comme ça.

Soit vous devez déplacer le vecteur dans la classe interne ou stocker une référence.

5

Contrairement à Java, les objets internes en C++ n'ont pas accès à un extérieur pointeur « this » ... si vous pensez qu'il peut y avoir des cas où il n'y a pas un à la référence.

solution de Richard Quirk est le plus proche, vous pouvez obtenir en C++

0

Vous pouvez simplifier par la construction suivante:

typedef std::vector<std::string> myList; 

vraiment pourquoi ne pas utiliser le vecteur STL directement? De cette façon, vous obtenez tous les algorithmes standards fonctionnent avec les données.

1

Bien que ce billet date de quelques années, je pourrais ajouter quelque chose d'utile. Bien que je dise que la conception de la classe dans le message original n'est pas très bonne, il y a des moments où il est utile d'avoir une classe incorporée pour accéder à la classe qui la contient. Cela peut facilement être fait sans stocker de pointeurs supplémentaires. Voici un exemple. Cela devrait fonctionner comme je l'ai pris d'un code existant et changé quelques noms autour. La clé est la macro EmbeddorOf. Fonctionne comme un charme.

//////////////////// .h /////////////////////// //

struct IReferenceCounted 
{ 
    virtual unsigned long AddRef() = 0; 
    virtual unsigned long Release() = 0; 
}; 

struct IFoo : public IReferenceCounted 
{ 
}; 

class Foo : public IFoo 
{ 
public: 
    static IFoo* Create(); 
    static IFoo* Create(IReferenceCounted* outer, IReferenceCounted** inner); 

private: 
    Foo(); 
    Foo(IReferenceCounted* outer); 
    ~Foo(); 

    // IReferenceCounted 

    unsigned long AddRef(); 
    unsigned long Release(); 

private: 
    struct EIReferenceCounted : IReferenceCounted 
    { 
     // IReferenceCounted 

     unsigned long AddRef(); 
     unsigned long Release(); 
    } _inner; 

    unsigned long _refs; 
    IReferenceCounted* _outer; 
}; 

////////////////fichier cpp /////////////////

#include <stdio.h> 
#include <stddef.h> 
#include "Foo.h" 

#define EmbeddorOf(class, member, this) \ 
    (class *) ((char *) this - offsetof(class, member)) 

// Foo 

Foo::Foo() : _refs(1), _outer(&this->_inner) 
{ 
} 

Foo::Foo(IReferenceCounted* outer) : _refs(1), _outer(outer) 
{ 
} 

Foo::~Foo() 
{ 
    printf("Foo::~Foo()\n"); 
} 

IFoo* Foo::Create() 
{ 
    return new Foo(); 
} 

IFoo* Foo::Create(IReferenceCounted* outer, IReferenceCounted** inner) 
{ 
    Foo* foo = new Foo(outer); 
    *inner = &foo->_inner; 
    return (IFoo*) foo; 
} 

// IReferenceCounted 

unsigned long Foo::AddRef() 
{ 
    printf("Foo::AddRef()\n"); 
    return this->_outer->AddRef(); 
} 

unsigned long Foo::Release() 
{ 
    printf("Foo::Release()\n"); 
    return this->_outer->Release(); 
} 

// Inner IReferenceCounted 

unsigned long Foo::EIReferenceCounted::AddRef() 
{ 
    Foo* pThis = EmbeddorOf(Foo, _inner, this); 
    return ++pThis->_refs; 
} 

unsigned long Foo::EIReferenceCounted::Release() 
{ 
    Foo* pThis = EmbeddorOf(Foo, _inner, this); 
    unsigned long refs = --pThis->_refs; 
    if (refs == 0) 
     { 

     // Artifically increment so that we won't try to destroy multiple 
     // times in the event that our destructor causes AddRef()'s or 
     // Releases(). 

     pThis->_refs = 1; 
     delete pThis; 
     } 
    return refs; 
} 

Nick