2008-10-25 10 views
12

estoy tratando de recopilar esta muy simple trozo de códigoC++ clases anidadas Conduciéndome loco

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"); 
} 

, ¿qué puedo hacer para hacer este trabajo sin crear más objetos que necesitaban o complicar las cosas ...

+3

Viniendo de Java :-) –

Respuesta

15

Agregue un par de constructores y un puntero a la clase principal.

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

se necesita el constructor myList(), por lo que registra instancias de sí mismo con la instancia de la variable miembro de clase interna. Entonces necesita el constructor de Items para almacenar el puntero a la instancia de la clase myList externa. Finalmente, en el método Agregar, debe hacer referencia a vec en la instancia myList almacenada.

Como señala Catskul, el constructor de elementos no debe hacer nada con el puntero de myList que recibe. También me gustaría decir que aunque esta respuesta está más cerca de la intención original, la respuesta de steveth45 es más cercana a lo que te gustaría hacer en un programa real.

+0

muchas gracias, esto funciona, pero yo tenía la esperanza de que una Existe una versión más simple, pero debo seguir lidiando con la obstinación de C++ :-(Espero que C++ 0x resuelva algunas de esas peculiaridades – SMeyers

+1

... pero tenga cuidado al pasar el MyList este puntero mientras MyList aún se está construyendo. El constructor de Items puede meterse en problemas si hace algo que termine usando MyList este puntero demasiado pronto. – Catskul

11

De esta manera no expones directamente a los miembros de tu clase. Tu ejemplo parece demasiado arquitectónico un poco. ¿Por qué poner un std :: vector en una clase y luego exponerlo como público?

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

El autor original probablemente necesite la construcción de clase interna para otras cosas que no menciona (por simplicidad de su exposición). Tienes razón sobre el softw son aspectos técnicos de ingeniería dada la información existente, pero el problema parece ser un problema de compilación de abstracción de "juguete" porque originalmente podría haber sido un algoritmo bastante complejo. Realmente no es importante, probablemente ya lo entiendas, solo digo ... –

2

Las clases internas solo están relacionadas por su nombre. No puede referirse al vector en la clase base así.

O bien debe mover el vector en la clase interna o almacenar una referencia a la misma.

5

A diferencia de Java, los objetos internos en C++ no tienen acceso a un puntero 'this' externo ... si lo piensas, puede haber casos en los que no haya uno de referencia. solución

Richard Quirk es la más cercana se puede obtener en C++

0

puede simplificar esto mediante la construcción siguiente:

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

Realmente ¿Por qué no usar el vector STL directamente? De esta forma obtiene todos los algoritmos estándar que funcionan con los datos .

1

Si bien esta publicación tiene algunos años I podría ser capaz de agregar algo útil. Aunque diré que el diseño de la clase en la publicación original no se ve tan bien, a veces es útil tener una clase incrustada para acceder a la clase contenedora. Esto puede hacerse fácilmente sin almacenar punteros adicionales. A continuación hay un ejemplo. Debería funcionar como lo tomé de un código existente y cambié algunos nombres. La clave es la macro EmbeddorOf. Funciona de maravilla.

//////////////////// .h file /////////////////////// //

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

////////////////.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