C ++ clases anidadas volviendome loca
Pregunta
Estoy tratando de compilar este pedazo de código muy simple
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 que esto funcione sin crear más objetos que sean necesarios o complicar demasiado las cosas ...
Solución
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");
}
Necesitas el constructor myList (), por lo que registra instancias de sí mismo con la instancia de la variable miembro de clase interna. Luego necesita el constructor de elementos para almacenar el puntero a la instancia de la clase myList externa. Finalmente, en el método Add, debe hacer referencia a vec en la instancia de myList almacenada.
Como señala Catskul, el constructor del elemento no debe hacer nada con el puntero myList que recibe. También me gustaría decir que aunque esta respuesta es más cercana a la intención original, la respuesta de steveth45 es más cercana a lo que querría hacer en un programa real.
Otros consejos
De esta manera, no está exponiendo directamente a los miembros de su clase. Tu ejemplo parece demasiado archivado. ¿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");
}
A diferencia de Java, los objetos internos en C ++ no tienen acceso a un puntero externo 'este' ... si lo piensas, puede haber casos en los que no haya uno al que hacer referencia.
La solución deRichard Quirk es la más cercana a C ++
Las clases internas solo están relacionadas por nombre. No puedes referirte al vector en la clase base de esa manera.
Debe mover el vector a la clase interna o guardar una referencia a él.
Si bien esta publicación tiene algunos años, podría ser capaz de agregarle algo útil. Si bien diré que el diseño de la clase en la publicación original no se ve tan bien, hay veces en que es útil tener una clase incorporada para poder acceder a la clase contenedora. Esto se puede hacer fácilmente sin almacenar punteros adicionales. A continuación se muestra un ejemplo. Debería funcionar como lo tomé de un código existente y cambié algunos nombres. La clave es la macro EmbeddorOf. Funciona como un encanto.
////////////////////// .h archivo ////////////////////////// /
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 archivo /////////////////
#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
Puedes simplificar esto mediante la siguiente construcción:
typedef std::vector<std::string> myList;
¿Realmente por qué no usas el vector STL directamente? De esta manera usted consigue que todos los algoritmos estándar trabajen con el datos.