Question

i am trying to compile this very simple piece of code

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

what can i do to make this work without creating more objects that needed or overcomplicating stuff...

Was it helpful?

Solution

Add a couple of constructors and a pointer to the parent class.

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

You need the myList() constructor, so it registers instances of itself with the instance of the inner class member variable. Then you need the Items constructor to store the pointer to the outer myList class instance. Finally in the Add method, you need to reference vec in the stored myList instance.

As Catskul points out, the Item constructor mustn't actually do anything with the myList pointer it receives. I'd also like to say that though this answer is closer to the original intent, steveth45's answer is closer to what you would want to do in a real program.

OTHER TIPS

This way you aren't exposing your class members directly. Your example seems over-architected a bit. Why put a std::vector into a class and then expose it as 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");
}

Unlike Java, inner objects in C++ don't have access to an outer 'this' pointer ... if you think about it there may be cases where there isn't one to reference.

Richard Quirk's solution is the nearest you can get in C++

Inner classes are only related by name. You can't refer to the vector in the base class like that.

You either need to move the vector in to the inner class or store a reference to it.

While this post is a few years old I might be able to add something useful to it. While I will say that the design of the class in the original post doesn't look that great, there are times where it's useful to have an embedded class be able to access the containing class. This can easily be done without storing extra pointers. Below is an example. It should work as I took it from some existing code and changed some names around. The key is the EmbeddorOf macro. Works like a charm.

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

#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

You can simplify this by the following construct:

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

Really why don't you use the STL vector directly? This way you get all the standard algorithms work with the data.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top