Подтвердить что ты не робот

С++ Вложенные классы заставляют меня сходить с ума

Я пытаюсь скомпилировать этот очень простой фрагмент кода

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

что я могу сделать, чтобы сделать эту работу, не создавая больше объектов, которые нуждаются в избыточном количестве вещей...

4b9b3361

Ответ 1

Добавьте пару конструкторов и указатель на родительский класс.

#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. Наконец, в методе "Добавить" вам нужно ссылаться на vec в сохраненном экземпляре myList.

Как указывает Catskul, конструктор Item фактически ничего не должен делать с указателем myList, который он получает. Я также хотел бы сказать, что хотя этот ответ ближе к первоначальному намерению, ответ steveth45 ближе к тому, что вы хотели бы сделать в реальной программе.

Ответ 2

Таким образом, вы не подвергаете себя непосредственно своим членам. Ваш пример немного завышен. Зачем класть 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");
}

Ответ 3

В отличие от Java, внутренние объекты в С++ не имеют доступа к внешнему указателю 'this'... если вы думаете об этом, могут быть случаи, когда некому ссылаться.

Решение Richard Quirk - это ближайшее, которое вы можете получить на С++

Ответ 4

Внутренние классы связаны только по имени. Вы не можете ссылаться на вектор в базовом классе.

Вам нужно либо переместить вектор во внутренний класс, либо сохранить ссылку на него.

Ответ 5

В то время как этой должности несколько лет, я мог бы добавить что-то полезное. Хотя я скажу, что дизайн класса в исходном сообщении не выглядит таким замечательным, бывают случаи, когда полезно иметь встроенный класс для доступа к содержащемуся классу. Это можно легко сделать без сохранения дополнительных указателей. Ниже приведен пример. Он должен работать, поскольку я взял его из какого-то существующего кода и изменил некоторые имена. Ключ - макрос 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() or
        // Releases().

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

Ник

Ответ 6

Это можно упростить с помощью следующей конструкции:

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

Действительно, почему вы не используете вектор STL напрямую? Таким образом, вы получаете все стандартные алгоритмы работы с данных.