Вложенные классы C++ сводят меня с ума
Вопрос
я пытаюсь скомпилировать этот очень простой фрагмент кода
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");
}
что я могу сделать, чтобы это работало, не создавая больше необходимых объектов и не усложняя вещи...
Решение
Добавьте пару конструкторов и указатель на родительский класс.
#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");
}
Вам нужен конструктор myList (), поэтому он регистрирует свои экземпляры вместе с экземпляром внутренней переменной-члена класса. Затем вам нужен конструктор Items для хранения указателя на внешний экземпляр класса myList. Наконец, в методе Add вам нужно сослаться на vec в сохраненном экземпляре myList.
Как указывает Catskul, конструктор Item не должен ничего делать с указателем myList, который он получает. Я также хотел бы сказать, что хотя этот ответ ближе к первоначальному замыслу, ответ steveth45 ближе к тому, что вы хотели бы сделать в реальной программе.
Другие советы
Таким образом, вы не выставляете своих учеников напрямую. Ваш пример, кажется, немного перегорожен. Зачем помещать std :: vector в класс, а затем выставлять его как открытый? Р>
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");
}
В отличие от Java, внутренние объекты в C ++ не имеют доступа к внешнему указателю 'this' ... если вы подумаете об этом, могут быть случаи, когда на них нет ссылок.
Решение Ричарда Квирка - самое близкое, которое вы можете получить в C ++
Внутренние классы связаны только по имени. Вы не можете ссылаться на вектор в базовом классе, как этот.
Вам нужно либо переместить вектор во внутренний класс, либо сохранить ссылку на него. Р>
Хотя этому посту уже несколько лет, я мощь иметь возможность добавить к нему что-то полезное.Хотя я скажу, что дизайн класса в исходном посте выглядит не так уж и хорошо, бывают случаи, когда полезно иметь встроенный класс, который сможет получить доступ к содержащему его классу.Это можно легко сделать без хранения дополнительных указателей.Ниже приведен пример.Это должно работать, поскольку я взял его из существующего кода и изменил некоторые имена.Ключом является макрос EmbeddorOf.Работает как шарм.
/////////////////// .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;
};
//////////////// .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;
}
Ник
Вы можете упростить это с помощью следующей конструкции:
typedef std::vector<std::string> myList;
Действительно, почему бы вам не использовать вектор STL напрямую? Таким образом, вы получаете все стандартные алгоритмы работы с данных. р>